From bbca86f44204e85c34edc0051d986ba6aa1e14fb Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 09:17:00 +0100 Subject: [PATCH 001/253] Less indentation; Renamed project name --- StartbitV2.ts | 3661 ++++++++++++++++++++++++------------------------- 1 file changed, 1821 insertions(+), 1840 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 9e8eec3..ddcdcb2 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -2,676 +2,657 @@ StartbitV2 package */ //% weight=10 icon="\uf013" color=#2896ff -namespace StartbitV2 { - - export enum startbit_Colors { - //% block="Red" - Red = 0x01, - //% block="Green" - Green = 0x02, - //% block="Blue" - Blue = 0x03, - //% block="Black" - Black = 0x04, - //% block="White" - White = 0x05, - //% block="None" - None = 0x06 - } - - export enum startbit_lineFollower { - //% blockId="S1_OUT_S2_OUT" block="Sensor1 and sensor2 are out black line" - S1_OUT_S2_OUT = 0x00, - //% blockId="S1_OUT_S2_IN" block="Sensor2 in black line but sensor1 not" - S1_OUT_S2_IN = 0x01, - //% blockId="S1_IN_S2_OUT" block="Sensor1 in black line but sensor2 not" - S1_IN_S2_OUT = 0x02, - //% blockId="S1_IN_S2_IN" block="Sensor1 and sensor2 are in black line " - S1_IN_S2_IN = 0x03 - } - - export enum startbit_Servos { - //% block="servo 1" - Servo1 = 0x01, - //% block="servo 2" - Servo2 = 0x02 - } - - export enum startbit_ultrasonicPort { - //% block="Port 1" - port1 = 0x01, - //% block="Port 2" - port2 = 0x02 - } - - let echoPin: DigitalPin; - let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="Initialize ultrasonic|port %port" - export function ultrasonic_init(port: startbit_ultrasonicPort) { - switch (port) { - case startbit_ultrasonicPort.port1: - echoPin = DigitalPin.P2; - trigPin = DigitalPin.P1; - break; - case startbit_ultrasonicPort.port2: - echoPin = DigitalPin.P14; - trigPin = DigitalPin.P13; - break; - } - } - - export enum startbit_touchKeyPort { - //% block="Port 1" - port1 = 0x01, - //% block="Port 2" - port2 = 0x02 - } - - let touchSensorPin: DigitalPin; - //% weight=93 blockId=touchSensor_init block="Initialize touchSensor|port %port" - export function touchSensor_init(port: startbit_touchKeyPort) { - switch (port) { - case startbit_touchKeyPort.port1: - touchSensorPin = DigitalPin.P1; - break; - case startbit_touchKeyPort.port2: - touchSensorPin = DigitalPin.P13; - break; - } - } - - export enum startbit_lineFollowPort { - //% block="Port 1" - port1 = 0x01 - } - - let lineFollowPin1: AnalogPin; - let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="Initialize lineFollowSensor|port %port" - export function lineFollowSensor_init(port: startbit_lineFollowPort){ - switch (port) { - case startbit_lineFollowPort.port1: - lineFollowPin1 = AnalogPin.P1; - lineFollowPin2 = AnalogPin.P2; - break; - } - } - - export enum startbit_PinIOStatus { - //% block="Low" - Low = 0x00, - //% block="High" - Hight = 0x01 - } - - export enum startbit_LineFollowerSensor { - //% block="Sensor 1" - LFSensor_1 = 0x00, - //% block="Sensor 2" - LFSensor_2 = 0x01 - } - - export enum startbit_busServoPort { - //% block="Port 6" - port6 = 0x06 - } - - export enum startbit_knobPort { - //% block="Port 1" - port1 = 0x01 - } - - let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="Initialize knobSensor|port %port" - export function knobSensor_init(port: startbit_knobPort){ - switch (port) { - case startbit_knobPort.port1: - knobPin = AnalogPin.P1; - break; - } - } - - export enum startbit_photosensitivePort { - //% block="Port 1" - port1 = 0x01 - } - - export enum startbit_PhotosensitiveSensor { - //% block="Port 1" - port1 = 0x00 - } - - let photosensitiveSensorPin1: AnalogPin; - let photosensitiveSensorPin2: DigitalPin; - //% weight=95 blockId=photosensitiveSensor_init block="Initialize photosensitiveSensor|port %port" - export function photosensitiveSensor_init(port: startbit_PhotosensitiveSensor) { - switch (port) { - case startbit_PhotosensitiveSensor.port1: - photosensitiveSensorPin1 = AnalogPin.P1; - photosensitiveSensorPin2 = DigitalPin.P2; - break; - } - } - - export enum startbit_fanPort { - //% block="Port 1" - port1, - //% block="Port 2" - port2 - } - - let fanPin1: AnalogPin; - let fanPin2: AnalogPin; - //% weight=98 blockId=fanSensor_init block="Initialize fanSensor|port %port" - export function fanSensor_init(port: startbit_fanPort){ - switch (port) { - case startbit_fanPort.port1: - fanPin1 = AnalogPin.P1; - fanPin2 = AnalogPin.P2; - break; - case startbit_fanPort.port2: - fanPin1 = AnalogPin.P13; - fanPin2 = AnalogPin.P14; - break; - } - } - - export enum startbit_iic { - //% block="Port 3" - port3 = 0x03, - //% block="Port 4" - port4 = 0x04, - //% block="Port 6" - port6 = 0x06 - } - //% weight=89 blockId=MP3_init block="Initialize MP3Module|port %port" - export function MP3_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } - - //% weight=87 blockId=ASR_init block="Initialize ASRModule|port %port" - export function ASR_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } - - //% weight=86 blockId=lineFollow_iic_init block="Initialize lineFollow iic|port %port" - export function lineFollow_iic_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } - - let avoidSensorPin: DigitalPin; - //% weight=96 blockId=avoidSensor_init block="Initialize avoidSensor|port %port" - export function avoidSensor_init(port: startbit_touchKeyPort) { - switch (port) { - case startbit_touchKeyPort.port1: - avoidSensorPin = DigitalPin.P1; - break; - case startbit_touchKeyPort.port2: - avoidSensorPin = DigitalPin.P13; - break; - } - } - - export enum startbit_servorange { - //% block="180" - range1 = 180, - //% block="270" - range2 =270 - } - - export enum startbit_digitaltubePort { - //% block="Port 1" - port1 = 0x01, - //% block="Port 2" - port2 = 0x02 - } - - export enum startbit_CmdType { - //% block="Invalid command" - NO_COMMAND = 0, - //% block="car run" - CAR_RUN = 1, - //% block="robot run" - ROBOT_RUN = 1, - //% block="Servo" - SERVO = 2, - //% block="Ultrasonic distance" - ULTRASONIC = 3, - //% block="Temperature" - TEMPERATURE = 4, - //% block="Light" - LIGHT = 6, - //% block="Voltage" - BAT = 7, - //% block="Rgb light" - RGB_LIGHT = 8, - //% block="Honk horn" - DIDI = 9, - //% block="Read firmware version" - VERSION = 10, - //% block="Read angle" - READ_ANGLE = 11, - //% block="Light belt" - RGB_BELT = 12, - //% block="WIFI mode" - WIFI_MODE = 13, - //% block="Get mac" - GET_MAC = 14, - //% block="Get hand cmd" - GET_HAND_CMD = 15 - } - - export enum startbit_CarRunCmdType { - //% block="Stop" - STOP = 0, - //% block="Go ahead" - GO_AHEAD, - //% block="Back" - GO_BACK, - //% block="Turn left" - TURN_LEFT, - //% block="Turn right" - TURN_RIGHT, - //% block="Go ahead slowly" - GO_AHEAD_SLOW, - //% block="Turn left slowly" - TURN_LEFT_SLOW, - //% block="Turn right slowly" - TURN_RIGHT_SLOW, - //% block="Invalid command" - COMMAND_ERRO - } - - /** - * Startbit initialization, please execute at boot time - */ - //% weight=100 blockId=startbit_Init block="Initialize StartbitV2" - export function startbit_Init() { - startbit_initRGBLight(); - serial.redirect( - SerialPin.P12, - SerialPin.P8, - BaudRate.BaudRate115200); - - basic.forever(() => { - getHandleCmd(); - if (0 < currentVoltage && currentVoltage < 6800 ) { - music.playTone(988, music.beat(BeatFraction.Whole)); - } - }); - basic.pause(2000); - } - - - let handleCmd: string = ""; - let currentVoltage: number = 0; - let lhRGBLight: StartbitRGBLight.LHstartbitRGBLight; - let lhRGBLightBelt: StartbitRGBLight.LHstartbitRGBLight; - - let P14_ad = 0; - - - let MESSAGE_MAC = 0xff; - let MESSAGE_ANGLE = 0x100; +namespace Informatiktheater { + export enum startbit_Colors { + //% block="Rot" + Red = 0x01, + //% block="Grün" + Green = 0x02, + //% block="Blau" + Blue = 0x03, + //% block="Schwarz" + Black = 0x04, + //% block="Weiss" + White = 0x05, + //% block="Leer" + None = 0x06, + } + + export enum startbit_lineFollower { + //% blockId="S1_OUT_S2_OUT" block="Sensor1 and sensor2 are out black line" + S1_OUT_S2_OUT = 0x00, + //% blockId="S1_OUT_S2_IN" block="Sensor2 in black line but sensor1 not" + S1_OUT_S2_IN = 0x01, + //% blockId="S1_IN_S2_OUT" block="Sensor1 in black line but sensor2 not" + S1_IN_S2_OUT = 0x02, + //% blockId="S1_IN_S2_IN" block="Sensor1 and sensor2 are in black line " + S1_IN_S2_IN = 0x03, + } + + export enum startbit_Servos { + //% block="servo 1" + Servo1 = 0x01, + //% block="servo 2" + Servo2 = 0x02, + } + + export enum startbit_ultrasonicPort { + //% block="Port 1" + port1 = 0x01, + //% block="Port 2" + port2 = 0x02, + } + + let echoPin: DigitalPin; + let trigPin: DigitalPin; + //% weight=91 blockId=ultrasonic_init block="Initialize ultrasonic|port %port" + export function ultrasonic_init(port: startbit_ultrasonicPort) { + switch (port) { + case startbit_ultrasonicPort.port1: + echoPin = DigitalPin.P2; + trigPin = DigitalPin.P1; + break; + case startbit_ultrasonicPort.port2: + echoPin = DigitalPin.P14; + trigPin = DigitalPin.P13; + break; + } + } + + export enum startbit_touchKeyPort { + //% block="Port 1" + port1 = 0x01, + //% block="Port 2" + port2 = 0x02, + } + + let touchSensorPin: DigitalPin; + //% weight=93 blockId=touchSensor_init block="Initialize touchSensor|port %port" + export function touchSensor_init(port: startbit_touchKeyPort) { + switch (port) { + case startbit_touchKeyPort.port1: + touchSensorPin = DigitalPin.P1; + break; + case startbit_touchKeyPort.port2: + touchSensorPin = DigitalPin.P13; + break; + } + } + + export enum startbit_lineFollowPort { + //% block="Port 1" + port1 = 0x01, + } + + let lineFollowPin1: AnalogPin; + let lineFollowPin2: AnalogPin; + //% weight=92 blockId=lineFollowSensor_init block="Initialize lineFollowSensor|port %port" + export function lineFollowSensor_init(port: startbit_lineFollowPort) { + switch (port) { + case startbit_lineFollowPort.port1: + lineFollowPin1 = AnalogPin.P1; + lineFollowPin2 = AnalogPin.P2; + break; + } + } + + export enum startbit_PinIOStatus { + //% block="Low" + Low = 0x00, + //% block="High" + Hight = 0x01, + } + + export enum startbit_LineFollowerSensor { + //% block="Sensor 1" + LFSensor_1 = 0x00, + //% block="Sensor 2" + LFSensor_2 = 0x01, + } + + export enum startbit_busServoPort { + //% block="Port 6" + port6 = 0x06, + } + + export enum startbit_knobPort { + //% block="Port 1" + port1 = 0x01, + } + + let knobPin: AnalogPin; + //% weight=99 blockId=knobSensor_init block="Initialize knobSensor|port %port" + export function knobSensor_init(port: startbit_knobPort) { + switch (port) { + case startbit_knobPort.port1: + knobPin = AnalogPin.P1; + break; + } + } + + export enum startbit_photosensitivePort { + //% block="Port 1" + port1 = 0x01, + } + + export enum startbit_PhotosensitiveSensor { + //% block="Port 1" + port1 = 0x00, + } + + let photosensitiveSensorPin1: AnalogPin; + let photosensitiveSensorPin2: DigitalPin; + //% weight=95 blockId=photosensitiveSensor_init block="Initialize photosensitiveSensor|port %port" + export function photosensitiveSensor_init( + port: startbit_PhotosensitiveSensor + ) { + switch (port) { + case startbit_PhotosensitiveSensor.port1: + photosensitiveSensorPin1 = AnalogPin.P1; + photosensitiveSensorPin2 = DigitalPin.P2; + break; + } + } + + export enum startbit_fanPort { + //% block="Port 1" + port1, + //% block="Port 2" + port2, + } + + let fanPin1: AnalogPin; + let fanPin2: AnalogPin; + export function fanSensor_init(port: startbit_fanPort) { + switch (port) { + case startbit_fanPort.port1: + fanPin1 = AnalogPin.P1; + fanPin2 = AnalogPin.P2; + break; + case startbit_fanPort.port2: + fanPin1 = AnalogPin.P13; + fanPin2 = AnalogPin.P14; + break; + } + } + + export enum startbit_iic { + //% block="Port 3" + port3 = 0x03, + //% block="Port 4" + port4 = 0x04, + //% block="Port 6" + port6 = 0x06, + } + //% weight=89 blockId=MP3_init block="Initialize MP3Module|port %port" + export function MP3_init(port: startbit_iic) { + switch (port) { + case startbit_iic.port3: + break; + case startbit_iic.port4: + break; + case startbit_iic.port6: + break; + } + } + + //% weight=87 blockId=ASR_init block="Initialize ASRModule|port %port" + export function ASR_init(port: startbit_iic) { + switch (port) { + case startbit_iic.port3: + break; + case startbit_iic.port4: + break; + case startbit_iic.port6: + break; + } + } + + //% weight=86 blockId=lineFollow_iic_init block="Initialize lineFollow iic|port %port" + export function lineFollow_iic_init(port: startbit_iic) { + switch (port) { + case startbit_iic.port3: + break; + case startbit_iic.port4: + break; + case startbit_iic.port6: + break; + } + } + + let avoidSensorPin: DigitalPin; + //% weight=96 blockId=avoidSensor_init block="Initialize avoidSensor|port %port" + export function avoidSensor_init(port: startbit_touchKeyPort) { + switch (port) { + case startbit_touchKeyPort.port1: + avoidSensorPin = DigitalPin.P1; + break; + case startbit_touchKeyPort.port2: + avoidSensorPin = DigitalPin.P13; + break; + } + } + + export enum startbit_servorange { + //% block="180" + range1 = 180, + //% block="270" + range2 = 270, + } + + export enum startbit_digitaltubePort { + //% block="Port 1" + port1 = 0x01, + //% block="Port 2" + port2 = 0x02, + } + + export enum startbit_CmdType { + //% block="Invalid command" + NO_COMMAND = 0, + //% block="car run" + CAR_RUN = 1, + //% block="robot run" + ROBOT_RUN = 1, + //% block="Servo" + SERVO = 2, + //% block="Ultrasonic distance" + ULTRASONIC = 3, + //% block="Temperature" + TEMPERATURE = 4, + //% block="Light" + LIGHT = 6, + //% block="Voltage" + BAT = 7, + //% block="Rgb light" + RGB_LIGHT = 8, + //% block="Honk horn" + DIDI = 9, + //% block="Read firmware version" + VERSION = 10, + //% block="Read angle" + READ_ANGLE = 11, + //% block="Light belt" + RGB_BELT = 12, + //% block="WIFI mode" + WIFI_MODE = 13, + //% block="Get mac" + GET_MAC = 14, + //% block="Get hand cmd" + GET_HAND_CMD = 15, + } + + export enum startbit_CarRunCmdType { + //% block="Stop" + STOP = 0, + //% block="Go ahead" + GO_AHEAD, + //% block="Back" + GO_BACK, + //% block="Turn left" + TURN_LEFT, + //% block="Turn right" + TURN_RIGHT, + //% block="Go ahead slowly" + GO_AHEAD_SLOW, + //% block="Turn left slowly" + TURN_LEFT_SLOW, + //% block="Turn right slowly" + TURN_RIGHT_SLOW, + //% block="Invalid command" + COMMAND_ERRO, + } - let i2cPortValid: boolean = true; - let connectStatus: boolean = false; - - let servo1Angle: number = 0xfff; - let servo2Angle: number = 0xfff; + /** + * Startbit initialization, please execute at boot time + */ + //% weight=100 blockId=startbit_Init block="Initialize StartbitV2" + export function startbit_Init() { + startbit_initRGBLight(); + serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); + + basic.forever(() => { + getHandleCmd(); + if (0 < currentVoltage && currentVoltage < 6800) { + music.playTone(988, music.beat(BeatFraction.Whole)); + } + }); + basic.pause(2000); + } + + let handleCmd: string = ""; + let currentVoltage: number = 0; + let lhRGBLight: StartbitRGBLight.LHstartbitRGBLight; + let lhRGBLightBelt: StartbitRGBLight.LHstartbitRGBLight; + + let P14_ad = 0; + + let MESSAGE_MAC = 0xff; + let MESSAGE_ANGLE = 0x100; + + let i2cPortValid: boolean = true; + let connectStatus: boolean = false; + + let servo1Angle: number = 0xfff; + let servo2Angle: number = 0xfff; + + let macStr: string = ""; + let actiongroup_finished = true; + + let Digitaltube: startbit_TM1640LEDs; + let TM1640_CMD1 = 0x40; + let TM1640_CMD2 = 0xc0; + let TM1640_CMD3 = 0x80; + let _SEGMENTS = [ + 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, + 0x39, 0x5e, 0x79, 0x71, + ]; - let macStr: string = ""; - let actiongroup_finished = true; - - let Digitaltube:startbit_TM1640LEDs - let TM1640_CMD1 = 0x40; - let TM1640_CMD2 = 0xC0; - let TM1640_CMD3 = 0x80; - let _SEGMENTS = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71]; - - /** - * Get the handle command. - */ - function getHandleCmd() { - let charStr: string = serial.readString(); - handleCmd = handleCmd.concat(charStr); - let cnt: number = countChar(handleCmd, "$"); - if (cnt == 0) - return; - let index = findIndexof(handleCmd, "$", 0); - if (index != -1) { - let cmd: string = handleCmd.substr(0, index); - if (cmd.charAt(0).compare("A") == 0) { - if (cmd.length == 7) { - let arg1Int: number = strToNumber(cmd.substr(1, 2)); - let arg2Int: number = strToNumber(cmd.substr(3, 2)); - let arg3Int: number = strToNumber(cmd.substr(5, 2)); - - P14_ad = arg1Int; - - if (arg3Int != -1) { - currentVoltage = arg3Int * 78.63; - currentVoltage = Math.round(currentVoltage); - } - - } else if (cmd.length == 5) { - actiongroup_finished = true; - } else { - - } - } - if (cmd.charAt(0).compare("C") == 0 && cmd.length == 11) { - if (lhRGBLightBelt != null) { - for (let i = 0; i < 10; i++) { - let color = converOneChar(cmd.charAt(i + 1)); - if (color != -1) - lhRGBLightBelt.setPixelColor(i, color); - } - lhRGBLightBelt.show(); - } - } - if (cmd.charAt(0).compare("M") == 0 && cmd.length == 18) { - macStr = cmd.substr(1, 17); - control.raiseEvent(MESSAGE_MAC, 1); - } - if (cmd.compare("WIFI_S_CONNECT") == 0) { - connectStatus = true; - } - if (cmd.compare("WIFI_S_DISCONNECT") == 0) { - connectStatus = false; - } - if (cmd.charAt(0).compare("S") == 0 && cmd.length == 5) { - let arg1Int: number = strToNumber(cmd.substr(1, 1)); - let arg2Str = cmd.substr(2, 3); - if (arg2Str.compare("XXX") == 0) { - return; - } - let arg2Int: number = 0; - if (arg2Str.charAt(0).compare("F") != 0) { - arg2Int = strToNumber(arg2Str); - } - if (arg2Int > 1000) - arg2Int = 1000; - if (arg1Int == 1) { - servo1Angle = mapRGB(arg2Int, 0, 1000, 0, 240); - servo1Angle -= 120; - control.raiseEvent(MESSAGE_ANGLE, 1); - } - else if (arg1Int == 2) { - servo2Angle = mapRGB(arg2Int, 0, 1000, 0, 240); - servo2Angle -= 120; - control.raiseEvent(MESSAGE_ANGLE, 2); - } - } + /** + * Get the handle command. + */ + function getHandleCmd() { + let charStr: string = serial.readString(); + handleCmd = handleCmd.concat(charStr); + let cnt: number = countChar(handleCmd, "$"); + if (cnt == 0) return; + let index = findIndexof(handleCmd, "$", 0); + if (index != -1) { + let cmd: string = handleCmd.substr(0, index); + if (cmd.charAt(0).compare("A") == 0) { + if (cmd.length == 7) { + let arg1Int: number = strToNumber(cmd.substr(1, 2)); + let arg2Int: number = strToNumber(cmd.substr(3, 2)); + let arg3Int: number = strToNumber(cmd.substr(5, 2)); + + P14_ad = arg1Int; + + if (arg3Int != -1) { + currentVoltage = arg3Int * 78.63; + currentVoltage = Math.round(currentVoltage); + } + } else if (cmd.length == 5) { + actiongroup_finished = true; + } else { } - handleCmd = ""; - } - - function checkADPortValue(value: number): number { - if (value == -1) - return 2; - if (value <= 0x2E) - return 0; - else if (value >= 0xAA) - return 1; - else - return 2;//未识别电平状态 - } - - function findIndexof(src: string, strFind: string, startIndex: number): number { - for (let i = startIndex; i < src.length; i++) { - if (src.charAt(i).compare(strFind) == 0) { - return i; - } + } + if (cmd.charAt(0).compare("C") == 0 && cmd.length == 11) { + if (lhRGBLightBelt != null) { + for (let i = 0; i < 10; i++) { + let color = converOneChar(cmd.charAt(i + 1)); + if (color != -1) lhRGBLightBelt.setPixelColor(i, color); + } + lhRGBLightBelt.show(); } - return -1; - } - - function countChar(src: string, strFind: string): number { - let cnt: number = 0; - for (let i = 0; i < src.length; i++) { - if (src.charAt(i).compare(strFind) == 0) { - cnt++; - } + } + if (cmd.charAt(0).compare("M") == 0 && cmd.length == 18) { + macStr = cmd.substr(1, 17); + control.raiseEvent(MESSAGE_MAC, 1); + } + if (cmd.compare("WIFI_S_CONNECT") == 0) { + connectStatus = true; + } + if (cmd.compare("WIFI_S_DISCONNECT") == 0) { + connectStatus = false; + } + if (cmd.charAt(0).compare("S") == 0 && cmd.length == 5) { + let arg1Int: number = strToNumber(cmd.substr(1, 1)); + let arg2Str = cmd.substr(2, 3); + if (arg2Str.compare("XXX") == 0) { + return; } - return cnt; - } - - function strToNumber(str: string): number { - let num: number = 0; - for (let i = 0; i < str.length; i++) { - let tmp: number = converOneChar(str.charAt(i)); - if (tmp == -1) - return -1; - if (i > 0) - num *= 16; - num += tmp; + let arg2Int: number = 0; + if (arg2Str.charAt(0).compare("F") != 0) { + arg2Int = strToNumber(arg2Str); } - return num; - } - - function decStrToNumber(str: string): number { - let num: number = 0; - for (let i = 0; i < str.length; i++) { - let tmp: number = converOneChar(str.charAt(i)); - if (tmp == -1) - return -1; - if (i > 0) - num *= 10; - num += tmp; + if (arg2Int > 1000) arg2Int = 1000; + if (arg1Int == 1) { + servo1Angle = mapRGB(arg2Int, 0, 1000, 0, 240); + servo1Angle -= 120; + control.raiseEvent(MESSAGE_ANGLE, 1); + } else if (arg1Int == 2) { + servo2Angle = mapRGB(arg2Int, 0, 1000, 0, 240); + servo2Angle -= 120; + control.raiseEvent(MESSAGE_ANGLE, 2); } - return num; - } + } + } + handleCmd = ""; + } + + function checkADPortValue(value: number): number { + if (value == -1) return 2; + if (value <= 0x2e) return 0; + else if (value >= 0xaa) return 1; + else return 2; //未识别电平状态 + } + + function findIndexof( + src: string, + strFind: string, + startIndex: number + ): number { + for (let i = startIndex; i < src.length; i++) { + if (src.charAt(i).compare(strFind) == 0) { + return i; + } + } + return -1; + } + + function countChar(src: string, strFind: string): number { + let cnt: number = 0; + for (let i = 0; i < src.length; i++) { + if (src.charAt(i).compare(strFind) == 0) { + cnt++; + } + } + return cnt; + } + + function strToNumber(str: string): number { + let num: number = 0; + for (let i = 0; i < str.length; i++) { + let tmp: number = converOneChar(str.charAt(i)); + if (tmp == -1) return -1; + if (i > 0) num *= 16; + num += tmp; + } + return num; + } + + function decStrToNumber(str: string): number { + let num: number = 0; + for (let i = 0; i < str.length; i++) { + let tmp: number = converOneChar(str.charAt(i)); + if (tmp == -1) return -1; + if (i > 0) num *= 10; + num += tmp; + } + return num; + } + + function converOneChar(str: string): number { + if (str.compare("0") >= 0 && str.compare("9") <= 0) { + return parseInt(str); + } else if (str.compare("A") >= 0 && str.compare("F") <= 0) { + if (str.compare("A") == 0) { + return 10; + } else if (str.compare("B") == 0) { + return 11; + } else if (str.compare("C") == 0) { + return 12; + } else if (str.compare("D") == 0) { + return 13; + } else if (str.compare("E") == 0) { + return 14; + } else if (str.compare("F") == 0) { + return 15; + } + return -1; + } else return -1; + } - function converOneChar(str: string): number { - if (str.compare("0") >= 0 && str.compare("9") <= 0) { - return parseInt(str); - } - else if (str.compare("A") >= 0 && str.compare("F") <= 0) { - if (str.compare("A") == 0) { - return 10; - } - else if (str.compare("B") == 0) { - return 11; - } - else if (str.compare("C") == 0) { - return 12; - } - else if (str.compare("D") == 0) { - return 13; - } - else if (str.compare("E") == 0) { - return 14; - } - else if (str.compare("F") == 0) { - return 15; - } - return -1; - } - else - return -1; - } - - /** - * Set the angle of servo 1 to 8, range of 0~270 degree - */ - //% weight=100 blockId=setServo block="Set pwm servo range %range|index %index|angle %angle|duration %duration" - //% angle.min=0 angle.max=270 - //% inlineInputMode=inline - //% subcategory=Servo/Motor - export function setPwmServo(range:startbit_servorange, index: number = 1, angle: number, duration: number = 300) { - - let position = mapRGB(angle, 0, range, 500, 2500); - - let buf = pins.createBuffer(10); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x08; - buf[3] = 0x03;//cmd type - buf[4] = 0x01; - buf[5] = duration & 0xff; - buf[6] = (duration >> 8) & 0xff; - buf[7] = index; - buf[8] = position & 0xff; - buf[9] = (position >> 8) & 0xff; - serial.writeBuffer(buf); - basic.pause(1); - } - - /** - * Set the angle of bus_servo, range:0~240 - */ - //% weight=98 blockId=setBusServo blockGap=50 block="Set bus servo index %index|angle %angle|duration %duration" - //% angle.min=0 angle.max=240 - //% inlineInputMode=inline - //% subcategory=Servo/Motor - export function setBusServo(index: number = 1, angle: number = 135, duration: number = 500) { - - let position = mapRGB(angle, 0, 240, 0, 1000); + /** + * Set the angle of servo 1 to 8, range of 0~270 degree + */ + //% weight=100 blockId=setServo block="Set pwm servo range %range|index %index|angle %angle|duration %duration" + //% angle.min=0 angle.max=270 + //% inlineInputMode=inline + //% subcategory=Servo/Motor + export function setPwmServo( + range: startbit_servorange, + index: number = 1, + angle: number, + duration: number = 300 + ) { + let position = mapRGB(angle, 0, range, 500, 2500); + + let buf = pins.createBuffer(10); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x08; + buf[3] = 0x03; //cmd type + buf[4] = 0x01; + buf[5] = duration & 0xff; + buf[6] = (duration >> 8) & 0xff; + buf[7] = index; + buf[8] = position & 0xff; + buf[9] = (position >> 8) & 0xff; + serial.writeBuffer(buf); + basic.pause(1); + } - let buf = pins.createBuffer(10); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x08; - buf[3] = 0x35;//cmd type - buf[4] = 0x01; - buf[5] = duration & 0xff; - buf[6] = (duration >> 8) & 0xff; - buf[7] = index; - buf[8] = position & 0xff; - buf[9] = (position >> 8) & 0xff; - serial.writeBuffer(buf); - basic.pause(1); - } - - /** - * Set the servo controller to run a actiongroup - * @param times Running times. eg: 1 - */ - //% weight=94 blockId=startbit_runActionGroup block="Run ActionGroup|index %index|times %times" - //% subcategory=Servo/Motor - export function startbit_runActionGroup(index: number, times: number = 1) { + /** + * Set the angle of bus_servo, range:0~240 + */ + //% weight=98 blockId=setBusServo blockGap=50 block="Set bus servo index %index|angle %angle|duration %duration" + //% angle.min=0 angle.max=240 + //% inlineInputMode=inline + //% subcategory=Servo/Motor + export function setBusServo( + index: number = 1, + angle: number = 135, + duration: number = 500 + ) { + let position = mapRGB(angle, 0, 240, 0, 1000); + + let buf = pins.createBuffer(10); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x08; + buf[3] = 0x35; //cmd type + buf[4] = 0x01; + buf[5] = duration & 0xff; + buf[6] = (duration >> 8) & 0xff; + buf[7] = index; + buf[8] = position & 0xff; + buf[9] = (position >> 8) & 0xff; + serial.writeBuffer(buf); + basic.pause(1); + } - let buf = pins.createBuffer(7); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x05; - buf[3] = 0x06;//cmd type CMD_ACTION_GROUP_RUN - buf[4] = index & 0xff; - buf[5] = times & 0xff; - buf[6] = (times >> 8) & 0xff; + /** + * Set the servo controller to run a actiongroup + * @param times Running times. eg: 1 + */ + //% weight=94 blockId=startbit_runActionGroup block="Run ActionGroup|index %index|times %times" + //% subcategory=Servo/Motor + export function startbit_runActionGroup(index: number, times: number = 1) { + let buf = pins.createBuffer(7); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x05; + buf[3] = 0x06; //cmd type CMD_ACTION_GROUP_RUN + buf[4] = index & 0xff; + buf[5] = times & 0xff; + buf[6] = (times >> 8) & 0xff; + + actiongroup_finished = false; + serial.writeBuffer(buf); + } - actiongroup_finished = false; - serial.writeBuffer(buf); - } - - /** - * Stop running actiongroup - */ - //% weight=92 blockId=startbit_stopnActionGroup block="Stop ActionGroup" - //% subcategory=Servo/Motor - export function startbit_stopActionGroup() { + /** + * Stop running actiongroup + */ + //% weight=92 blockId=startbit_stopnActionGroup block="Stop ActionGroup" + //% subcategory=Servo/Motor + export function startbit_stopActionGroup() { + let buf = pins.createBuffer(7); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x02; + buf[3] = 0x07; //cmd type CMD_ACTION_GROUP_STOP + + actiongroup_finished = false; + serial.writeBuffer(buf); + } - let buf = pins.createBuffer(7); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x02; - buf[3] = 0x07;//cmd type CMD_ACTION_GROUP_STOP - - actiongroup_finished = false; - serial.writeBuffer(buf); - } - - /** - * Wait for Actiongroup Finishing - */ - //% weight=93 blockId=startbit_actionRunover block="Action run over" - //% subcategory=Servo/Motor - export function startbit_actionRunover(): boolean { - // let ret = false; - if (actiongroup_finished == true) { - // ret = true; - actiongroup_finished = true; - } - else { - actiongroup_finished = false; - } - return actiongroup_finished; - } + /** + * Wait for Actiongroup Finishing + */ + //% weight=93 blockId=startbit_actionRunover block="Action run over" + //% subcategory=Servo/Motor + export function startbit_actionRunover(): boolean { + // let ret = false; + if (actiongroup_finished == true) { + // ret = true; + actiongroup_finished = true; + } else { + actiongroup_finished = false; + } + return actiongroup_finished; + } + + // /** + // * Send read startbit servos angle command + // */ + // //% weight=99 blockId=startbit_readAngle block="Send |%servo|angle command " + // //% subcategory=Servo/Motor + // export function startbit_readAngle(servo: startbit_Servos) { + // let buf = pins.createBuffer(6); + // buf[0] = 0x55; + // buf[1] = 0x55; + // buf[2] = 0x04; + // buf[3] = 0x3E;//cmd type + // buf[4] = 0x05; + // buf[5] = servo; + // serial.writeBuffer(buf); + // } + + // /** + // * Do someting when Startbit receive angle + // * @param body code to run when event is raised + // */ + // //% weight=97 blockId=onStartbit_getAngle blockGap=50 block="on Startbit|%servo|get angle" + // //% subcategory=Servo/Motor + // export function onStartbit_getAngle(servo: startbit_Servos, body: Action) { + // control.onEvent(MESSAGE_ANGLE, servo, body); + // } + + // /** + // * Get servos angle + // */ + // //% weight=98 blockId=getServosAngle block="Get|%servo|angle(-120~120)" + // //% subcategory=Servo/Motor + // export function getServosAngle(servo: startbit_Servos): number { + // if (servo == startbit_Servos.Servo1) { + // return servo1Angle; + // } + // else if (servo == startbit_Servos.Servo2) { + // return servo2Angle; + // } + // else + // return 0xFFF; + // } - -// /** -// * Send read startbit servos angle command -// */ -// //% weight=99 blockId=startbit_readAngle block="Send |%servo|angle command " -// //% subcategory=Servo/Motor -// export function startbit_readAngle(servo: startbit_Servos) { -// let buf = pins.createBuffer(6); -// buf[0] = 0x55; -// buf[1] = 0x55; -// buf[2] = 0x04; -// buf[3] = 0x3E;//cmd type -// buf[4] = 0x05; -// buf[5] = servo; -// serial.writeBuffer(buf); -// } - - -// /** -// * Do someting when Startbit receive angle -// * @param body code to run when event is raised -// */ -// //% weight=97 blockId=onStartbit_getAngle blockGap=50 block="on Startbit|%servo|get angle" -// //% subcategory=Servo/Motor -// export function onStartbit_getAngle(servo: startbit_Servos, body: Action) { -// control.onEvent(MESSAGE_ANGLE, servo, body); -// } - - -// /** -// * Get servos angle -// */ -// //% weight=98 blockId=getServosAngle block="Get|%servo|angle(-120~120)" -// //% subcategory=Servo/Motor -// export function getServosAngle(servo: startbit_Servos): number { -// if (servo == startbit_Servos.Servo1) { -// return servo1Angle; -// } -// else if (servo == startbit_Servos.Servo2) { -// return servo2Angle; -// } -// else -// return 0xFFF; -// } - - /** - * Send robot attitude to the servo controller - * @param pitch eg: 0 - * @param roll eg: 0 - */ - //% weight=91 blockId=startbit_sendAttitude block="Send pitch|%pitch|and roll|%roll" - /* + /** + * Send robot attitude to the servo controller + * @param pitch eg: 0 + * @param roll eg: 0 + */ + //% weight=91 blockId=startbit_sendAttitude block="Send pitch|%pitch|and roll|%roll" + /* export function startbit_sendAttitude(pitch: number, roll: number) { pitch < -90 ? -90 : pitch; pitch > 90 ? 90 : pitch; @@ -688,1281 +669,1281 @@ namespace StartbitV2 { serial.writeBuffer(buf); } */ - - /** - * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. - */ - //% weight=96 blockId=startbit_setMotorSpeed block="Set motor1 speed(-100~100)|%speed1|and motor2|speed %speed2" - //% speed1.min=-100 speed1.max=100 - //% speed2.min=-100 speed2.max=100 - //% subcategory=Servo/Motor - export function startbit_setMotorSpeed(speed1: number, speed2: number) { - if (speed1 > 100 || speed1 < -100 || speed2 > 100 || speed2 < -100) { - return; - } - speed1 = speed1 * -1; - speed2 = speed2 * -1; - let buf = pins.createBuffer(6); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x04; - buf[3] = 0x32;//cmd type - buf[4] = speed1; - buf[5] = speed2; - serial.writeBuffer(buf); - } - - /** - * Set the speed of the fan, range of -100~100. - */ - //% weight=95 blockId=startbit_setFanSpeed blockGap=50 block="Set fan speed(-100~100)|%speed1" - //% speed1.min=-100 speed1.max=100 - //% subcategory=Servo/Motor - export function startbit_setFanSpeed(speed1: number) { - if (speed1 > 100 || speed1 < -100) { - return; - } - - if (speed1 < 0) { - pins.analogWritePin(fanPin2, 0); - pins.analogWritePin(fanPin1, pins.map(-speed1, 0, 100, 0, 1023)); - } - else if (speed1 > 0) { - pins.analogWritePin(fanPin1, 0); - pins.analogWritePin(fanPin2, pins.map(speed1, 0, 100, 0, 1023)); - } - else { - pins.analogWritePin(fanPin2, 0); - pins.analogWritePin(fanPin1, 0); - } - - } - - /** - * Get startbit current voltage,the unit is mV - */ - //% weight=93 blockGap=50 blockId=startbit_getBatVoltage block="Get startbit current voltage (mV)" - //% subcategory=Sensor - export function startbit_getBatVoltage(): number { - return currentVoltage; - } - - /** - * TM1640 LED display - */ - export class startbit_TM1640LEDs { - buf: Buffer; - clk: DigitalPin; - dio: DigitalPin; - _ON: number; - brightness: number; - count: number; // number of LEDs - - /** - * initial TM1640 - */ - init(): void { - pins.digitalWritePin(this.clk, 0); - pins.digitalWritePin(this.dio, 0); - this._ON = 8; - this.buf = pins.createBuffer(this.count); - this.clear(); - } - - /** - * Start - */ - _start() { - pins.digitalWritePin(this.dio, 0); - pins.digitalWritePin(this.clk, 0); - } - - /** - * Stop - */ - _stop() { - pins.digitalWritePin(this.dio, 0); - pins.digitalWritePin(this.clk, 1); - pins.digitalWritePin(this.dio, 1); - } - - /** - * send command1 - */ - _write_data_cmd() { - this._start(); - this._write_byte(TM1640_CMD1); - this._stop(); - } - - /** - * send command3 - */ - _write_dsp_ctrl() { - this._start(); - this._write_byte(TM1640_CMD3 | this._ON | this.brightness); - this._stop(); - } - - /** - * send a byte to 2-wire interface - */ - _write_byte(b: number) { - for (let i = 0; i < 8; i++) { - pins.digitalWritePin(this.clk, 0); - pins.digitalWritePin(this.dio, (b >> i) & 1); - pins.digitalWritePin(this.clk, 1); - - } - pins.digitalWritePin(this.clk, 1); - pins.digitalWritePin(this.clk, 0); - } - - intensity(val: number = 7) { - if (val < 1) { - this.off(); - return; - } - if (val > 8) val = 8; - this._ON = 8; - this.brightness = val - 1; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } - - /** - * set data to TM1640, with given bit - */ - _dat(bit: number, dat: number) { - this._write_data_cmd(); - this._start(); - this._write_byte(TM1640_CMD2 | (bit % this.count)) - this._write_byte(dat); - this._stop(); - this._write_dsp_ctrl(); - } - - - showbit(num: number = 5, bit: number = 0) { - this.buf[bit % this.count] = _SEGMENTS[num % 16] - this._dat(bit, _SEGMENTS[num % 16]) - } - showNumber(num: number) { - if (num < 0) { - this._dat(0, 0x40) // '-' - num = -num - } - else - this.showbit(Math.idiv(num, 1000) % 10) - this.showbit(num % 10, 3) - this.showbit(Math.idiv(num, 10) % 10, 2) - this.showbit(Math.idiv(num, 100) % 10, 1) - } - - showHex(num: number) { - if (num < 0) { - this._dat(0, 0x40) // '-' - num = -num - } - else - this.showbit((num >> 12) % 16) - this.showbit(num % 16, 3) - this.showbit((num >> 4) % 16, 2) - this.showbit((num >> 8) % 16, 1) - } - - - showDP(bit: number = 1, show: boolean = true) { - bit = bit % this.count - if (show) this._dat(bit, this.buf[bit] | 0x80) - else this._dat(bit, this.buf[bit] & 0x7F) - } - - clear() { - for (let i = 0; i < this.count; i++) { - this._dat(i, 0) - this.buf[i] = 0 - } - } - - on() { - this._ON = 8; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } + /** + * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. + */ + //% weight=96 blockId=startbit_setMotorSpeed block="Set motor1 speed(-100~100)|%speed1|and motor2|speed %speed2" + //% speed1.min=-100 speed1.max=100 + //% speed2.min=-100 speed2.max=100 + //% subcategory=Servo/Motor + export function startbit_setMotorSpeed(speed1: number, speed2: number) { + if (speed1 > 100 || speed1 < -100 || speed2 > 100 || speed2 < -100) { + return; + } + speed1 = speed1 * -1; + speed2 = speed2 * -1; + let buf = pins.createBuffer(6); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x04; + buf[3] = 0x32; //cmd type + buf[4] = speed1; + buf[5] = speed2; + serial.writeBuffer(buf); + } - off() { - this._ON = 0; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } - } - /** - * 创建 TM1640 对象. - * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 - * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 - * @param intensity the brightness of the LED, eg: 7 - * @param count the count of the LED, eg: 4 - */ - function startbit_TM1640create(port: startbit_digitaltubePort, intensity: number, count: number): startbit_TM1640LEDs { - let digitaltube = new startbit_TM1640LEDs(); - switch (port) { - case startbit_digitaltubePort.port1: - digitaltube.clk = DigitalPin.P2; - digitaltube.dio = DigitalPin.P1; - break; - case startbit_digitaltubePort.port2: - digitaltube.clk = DigitalPin.P14; - digitaltube.dio = DigitalPin.P13; - break; - } + /** + * Set the speed of the fan, range of -100~100. + */ + //% weight=95 blockId=startbit_setFanSpeed blockGap=50 block="Set fan speed(-100~100)|%speed1" + //% speed1.min=-100 speed1.max=100 + //% subcategory=Servo/Motor + export function startbit_setFanSpeed(speed1: number) { + if (speed1 > 100 || speed1 < -100) { + return; + } + + if (speed1 < 0) { + pins.analogWritePin(fanPin2, 0); + pins.analogWritePin(fanPin1, pins.map(-speed1, 0, 100, 0, 1023)); + } else if (speed1 > 0) { + pins.analogWritePin(fanPin1, 0); + pins.analogWritePin(fanPin2, pins.map(speed1, 0, 100, 0, 1023)); + } else { + pins.analogWritePin(fanPin2, 0); + pins.analogWritePin(fanPin1, 0); + } + } - if ((count < 1) || (count > 5)) count = 4; - digitaltube.count = count; - digitaltube.brightness = intensity; - digitaltube.init(); - return digitaltube; - } + /** + * Get startbit current voltage,the unit is mV + */ + //% weight=93 blockGap=50 blockId=startbit_getBatVoltage block="Get startbit current voltage (mV)" + //% subcategory=Sensor + export function startbit_getBatVoltage(): number { + return currentVoltage; + } /** - * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 - * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 - * @param intensity the brightness of the LED, eg: 7 - * @param count the count of the LED, eg: 4 - */ - //% weight=90 blockId=startbit_digitaltube blockGap=50 block="digitaltube|%port|intensity %intensity|LED count %count" - export function startbit_digitaltube(port: startbit_digitaltubePort, intensity: number, count: number) { - Digitaltube = startbit_TM1640create(port, intensity, count); - } + * TM1640 LED display + */ + export class startbit_TM1640LEDs { + buf: Buffer; + clk: DigitalPin; + dio: DigitalPin; + _ON: number; + brightness: number; + count: number; // number of LEDs /** - * show a number. - * @param num is a number, eg: 0 + * initial TM1640 */ - //% weight=91 blockId=startbit_showNumber block="digitaltube show number| %num" - //% subcategory=LED - export function startbit_showNumber(num: number) { - Digitaltube.showNumber(num); + init(): void { + pins.digitalWritePin(this.clk, 0); + pins.digitalWritePin(this.dio, 0); + this._ON = 8; + this.buf = pins.createBuffer(this.count); + this.clear(); } /** - * show a number in given position. - * @param num number will show, eg: 5 - * @param bit the position of the LED, eg: 0 + * Start */ - //% weight=89 blockId=startbit_showbit block="digitaltube show digit| %num|at %bit" - //% subcategory=LED - export function startbit_showbit(num: number = 5, bit: number = 0) { - Digitaltube.showbit(num, bit); + _start() { + pins.digitalWritePin(this.dio, 0); + pins.digitalWritePin(this.clk, 0); } /** - * show a hex number. - * @param num is a hex number, eg: 0 + * Stop */ - //% weight=90 blockId=startbit_showhex block="digitaltube show hex number| %num" - //% subcategory=LED - export function startbit_showhex(num: number) { - Digitaltube.showHex(num); + _stop() { + pins.digitalWritePin(this.dio, 0); + pins.digitalWritePin(this.clk, 1); + pins.digitalWritePin(this.dio, 1); } /** - * show or hide dot point. - * @param bit is the position, eg: 1 - * @param show is show/hide dp, eg: true - */ - //% weight=88 blockId=startbit_showDP block="digitaltube DotPoint at| %bit|show %show" - //% subcategory=LED - export function startbit_showDP(bit: number = 1, show: boolean = true) { - Digitaltube.showDP(bit, show); - } - - /** - * set TM1640 intensity, range is [0-8], 0 is off. - * @param val the brightness of the TM1640, eg: 7 + * send command1 */ - //% weight=92 blockId=startbit_intensity block=" digitaltube set intensity %val" - //% subcategory=LED - export function startbit_intensity(val: number = 7) { - Digitaltube.intensity(val); - } + _write_data_cmd() { + this._start(); + this._write_byte(TM1640_CMD1); + this._stop(); + } /** - * turn off LED. + * send command3 */ - //% weight=86 blockId=startbit_off block="turn off digitaltube" - //% subcategory=LED - export function startbit_off() { - Digitaltube.off(); + _write_dsp_ctrl() { + this._start(); + this._write_byte(TM1640_CMD3 | this._ON | this.brightness); + this._stop(); } /** - * turn on LED. + * send a byte to 2-wire interface */ - //% weight=87 blockId=startbit_on block="turn on digitaltube" - //% subcategory=LED - export function startbit_on() { - Digitaltube.on(); + _write_byte(b: number) { + for (let i = 0; i < 8; i++) { + pins.digitalWritePin(this.clk, 0); + pins.digitalWritePin(this.dio, (b >> i) & 1); + pins.digitalWritePin(this.clk, 1); + } + pins.digitalWritePin(this.clk, 1); + pins.digitalWritePin(this.clk, 0); + } + + intensity(val: number = 7) { + if (val < 1) { + this.off(); + return; + } + if (val > 8) val = 8; + this._ON = 8; + this.brightness = val - 1; + this._write_data_cmd(); + this._write_dsp_ctrl(); } /** - * clear LED. + * set data to TM1640, with given bit */ - //%weight=85 blockId=startbit_clear blockGap=50 block="clear digitaltube" - //% subcategory=LED - export function startbit_clear() { - Digitaltube.clear(); - } - - const APDS9960_I2C_ADDR = 0x39; - const APDS9960_ID_1 = 0xA8; - const APDS9960_ID_2 = 0x9C; - /* APDS-9960 register addresses */ - const APDS9960_ENABLE = 0x80; - const APDS9960_ATIME = 0x81; - const APDS9960_WTIME = 0x83; - const APDS9960_AILTL = 0x84; - const APDS9960_AILTH = 0x85; - const APDS9960_AIHTL = 0x86; - const APDS9960_AIHTH = 0x87; - const APDS9960_PERS = 0x8C; - const APDS9960_CONFIG1 = 0x8D; - const APDS9960_PPULSE = 0x8E; - const APDS9960_CONTROL = 0x8F; - const APDS9960_CONFIG2 = 0x90; - const APDS9960_ID = 0x92; - const APDS9960_STATUS = 0x93; - const APDS9960_CDATAL = 0x94; - const APDS9960_CDATAH = 0x95; - const APDS9960_RDATAL = 0x96; - const APDS9960_RDATAH = 0x97; - const APDS9960_GDATAL = 0x98; - const APDS9960_GDATAH = 0x99; - const APDS9960_BDATAL = 0x9A; - const APDS9960_BDATAH = 0x9B; - const APDS9960_POFFSET_UR = 0x9D; - const APDS9960_POFFSET_DL = 0x9E; - const APDS9960_CONFIG3 = 0x9F; - const APDS9960_GCONF4 = 0xAB; - const APDS9960_AICLEAR = 0xE7; - - - /* LED Drive values */ - const LED_DRIVE_100MA = 0; - - /* ALS Gain (AGAIN) values */ - const AGAIN_4X = 1; - - /* Default values */ - const DEFAULT_ATIME = 219; // 103ms - const DEFAULT_WTIME = 246; // 27ms - const DEFAULT_PROX_PPULSE = 0x87; // 16us, 8 pulses - const DEFAULT_POFFSET_UR = 0; // 0 offset - const DEFAULT_POFFSET_DL = 0; // 0 offset - const DEFAULT_CONFIG1 = 0x60; // No 12x wait (WTIME) factor - const DEFAULT_AILT = 0xFFFF; // Force interrupt for calibration - const DEFAULT_AIHT = 0; - const DEFAULT_PERS = 0x11; // 2 consecutive prox or ALS for int. - const DEFAULT_CONFIG2 = 0x01; // No saturation interrupts or LED boost - const DEFAULT_CONFIG3 = 0; // Enable all photodiodes, no SAI - const DEFAULT_LDRIVE = LED_DRIVE_100MA; - const DEFAULT_AGAIN = AGAIN_4X; - - const OFF = 0; - const POWER = 0; - const AMBIENT_LIGHT = 1; - const ALL = 7; - - const red_wb = 2130; - const green_wb = 3500; - const blue_wb = 4620; - - function i2cwrite(reg: number, value: number) { - let buf = pins.createBuffer(2); - buf[0] = reg; - buf[1] = value; - pins.i2cWriteBuffer(APDS9960_I2C_ADDR, buf); + _dat(bit: number, dat: number) { + this._write_data_cmd(); + this._start(); + this._write_byte(TM1640_CMD2 | bit % this.count); + this._write_byte(dat); + this._stop(); + this._write_dsp_ctrl(); } - function i2cread(reg: number): number { - pins.i2cWriteNumber(APDS9960_I2C_ADDR, reg, NumberFormat.UInt8BE); - let val = pins.i2cReadNumber(APDS9960_I2C_ADDR, NumberFormat.UInt8BE); - return val; + showbit(num: number = 5, bit: number = 0) { + this.buf[bit % this.count] = _SEGMENTS[num % 16]; + this._dat(bit, _SEGMENTS[num % 16]); } - - function InitColor(): boolean { - let id = i2cread(APDS9960_ID); - // serial.writeLine("id:") - // serial.writeNumber(id); - // if (!(id == APDS9960_ID_1 || id == APDS9960_ID_2)) { - // return false; - // } - // serial.writeLine("set mode:") - setMode(ALL, OFF); - i2cwrite(APDS9960_ATIME, DEFAULT_ATIME); - i2cwrite(APDS9960_WTIME, DEFAULT_WTIME); - i2cwrite(APDS9960_PPULSE, DEFAULT_PROX_PPULSE); - i2cwrite(APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR); - i2cwrite(APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL); - i2cwrite(APDS9960_CONFIG1, DEFAULT_CONFIG1); - setLEDDrive(DEFAULT_LDRIVE); - setAmbientLightGain(DEFAULT_AGAIN); - setLightIntLowThreshold(DEFAULT_AILT); - setLightIntHighThreshold(DEFAULT_AIHT); - i2cwrite(APDS9960_PERS, DEFAULT_PERS); - i2cwrite(APDS9960_CONFIG2, DEFAULT_CONFIG2); - i2cwrite(APDS9960_CONFIG3, DEFAULT_CONFIG3); - return true; + showNumber(num: number) { + if (num < 0) { + this._dat(0, 0x40); // '-' + num = -num; + } else this.showbit(Math.idiv(num, 1000) % 10); + this.showbit(num % 10, 3); + this.showbit(Math.idiv(num, 10) % 10, 2); + this.showbit(Math.idiv(num, 100) % 10, 1); } - function setLEDDrive(drive: number) { - let val = i2cread(APDS9960_CONTROL); - /* Set bits in register to given value */ - drive &= 0b00000011; - drive = drive << 6; - val &= 0b00111111; - val |= drive; - i2cwrite(APDS9960_CONTROL, val); + showHex(num: number) { + if (num < 0) { + this._dat(0, 0x40); // '-' + num = -num; + } else this.showbit((num >> 12) % 16); + this.showbit(num % 16, 3); + this.showbit((num >> 4) % 16, 2); + this.showbit((num >> 8) % 16, 1); } - function setLightIntLowThreshold(threshold: number) { - let val_low = threshold & 0x00FF; - let val_high = (threshold & 0xFF00) >> 8; - i2cwrite(APDS9960_AILTL, val_low); - i2cwrite(APDS9960_AILTH, val_high); + showDP(bit: number = 1, show: boolean = true) { + bit = bit % this.count; + if (show) this._dat(bit, this.buf[bit] | 0x80); + else this._dat(bit, this.buf[bit] & 0x7f); } - function setLightIntHighThreshold(threshold: number) { - let val_low = threshold & 0x00FF; - let val_high = (threshold & 0xFF00) >> 8; - i2cwrite(APDS9960_AIHTL, val_low); - i2cwrite(APDS9960_AIHTH, val_high); + clear() { + for (let i = 0; i < this.count; i++) { + this._dat(i, 0); + this.buf[i] = 0; + } } - - function rgb2hue(r: number, g: number, b: number): number { - let max = Math.max(r, Math.max(g, b)) - let min = Math.min(r, Math.min(g, b)) - let c = max - min; - let hue = 0; - let segment = 0; - let shift = 0; - if (c == 0) - return 0; - if ((r > g) && (r > b)) { - segment = (60.0 * (g - b)) / c; - if (segment < 0) - hue = segment + 360; - } - else if ((g > b) && (g > r)) { - segment = (60.0 * (b - r)) / c; - hue = segment + 120; - } - else if ((b > g) && (b > r)) { - segment = (60.0 * (r - g)) / c; - hue = segment + 240; - } - return hue; + on() { + this._ON = 8; + this._write_data_cmd(); + this._write_dsp_ctrl(); } - function setMode(mode: number, enable: number) { - let reg_val = getMode(); - /* Change bit(s) in ENABLE register */ - enable = enable & 0x01; - if (mode >= 0 && mode <= 6) { - if (enable > 0) { - reg_val |= (1 << mode); - } - else { - //reg_val &= ~(1 << mode); - reg_val &= (0xff - (1 << mode)); - } - } - else if (mode == ALL) { - if (enable > 0) { - reg_val = 0x7F; - } - else { - reg_val = 0x00; - } - } - i2cwrite(APDS9960_ENABLE, reg_val); - } - - function getMode(): number { - let enable_value = i2cread(APDS9960_ENABLE); - return enable_value; + off() { + this._ON = 0; + this._write_data_cmd(); + this._write_dsp_ctrl(); } + } + /** + * 创建 TM1640 对象. + * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 + * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 + * @param intensity the brightness of the LED, eg: 7 + * @param count the count of the LED, eg: 4 + */ + function startbit_TM1640create( + port: startbit_digitaltubePort, + intensity: number, + count: number + ): startbit_TM1640LEDs { + let digitaltube = new startbit_TM1640LEDs(); + switch (port) { + case startbit_digitaltubePort.port1: + digitaltube.clk = DigitalPin.P2; + digitaltube.dio = DigitalPin.P1; + break; + case startbit_digitaltubePort.port2: + digitaltube.clk = DigitalPin.P14; + digitaltube.dio = DigitalPin.P13; + break; + } + + if (count < 1 || count > 5) count = 4; + digitaltube.count = count; + digitaltube.brightness = intensity; + digitaltube.init(); + return digitaltube; + } - function enableLightSensor(interrupts: boolean) { - setAmbientLightGain(DEFAULT_AGAIN); - if (interrupts) { - setAmbientLightIntEnable(1); - } - else { - setAmbientLightIntEnable(0); - } - enablePower(); - setMode(AMBIENT_LIGHT, 1); - } - - function setAmbientLightGain(drive: number) { - let val = i2cread(APDS9960_CONTROL); - /* Set bits in register to given value */ - drive &= 0b00000011; - val &= 0b11111100; - val |= drive; - i2cwrite(APDS9960_CONTROL, val); - } - - function getAmbientLightGain(): number { - let val = i2cread(APDS9960_CONTROL); - val &= 0b00000011; - return val; - } - - function enablePower() { - setMode(POWER, 1); - } - - function setAmbientLightIntEnable(enable: number) { - let val = i2cread(APDS9960_ENABLE); - /* Set bits in register to given value */ - enable &= 0b00000001; - enable = enable << 4; - val &= 0b11101111; - val |= enable; - i2cwrite(APDS9960_ENABLE, val); - } - - function readAmbientLight(): number { - let val = i2cread(APDS9960_CDATAL); - let val_byte = i2cread(APDS9960_CDATAH); - val = val + val_byte * 256; - return val; - } - - - /** - * Initialize the color sensor,please execute at boot time - */ - //% weight=88 blockId=startbit_init_colorSensor block="Initialize color sensor port at %port" - export function startbit_init_colorSensor(port: startbit_iic) { - InitColor(); - enableLightSensor(true); - control.waitMicros(100); - } + /** + * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 + * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 + * @param intensity the brightness of the LED, eg: 7 + * @param count the count of the LED, eg: 4 + */ + //% weight=90 blockId=startbit_digitaltube blockGap=50 block="digitaltube|%port|intensity %intensity|LED count %count" + export function startbit_digitaltube( + port: startbit_digitaltubePort, + intensity: number, + count: number + ) { + Digitaltube = startbit_TM1640create(port, intensity, count); + } - /** - * Color sensor return the color. - */ - //% weight=99 blockId=startbit_checkCurrentColor block="Current color %color" - //% subcategory=Sensor - export function startbit_checkCurrentColor(color: startbit_Colors): boolean { - let c = i2cread(APDS9960_CDATAL) + i2cread(APDS9960_CDATAH) * 256; - let r = i2cread(APDS9960_RDATAL) + i2cread(APDS9960_RDATAH) * 256; - let g = i2cread(APDS9960_GDATAL) + i2cread(APDS9960_GDATAH) * 256; - let b = i2cread(APDS9960_BDATAL) + i2cread(APDS9960_BDATAH) * 256; - - // serial.writeNumber(c); - // serial.writeLine("->ccc"); - // serial.writeNumber(r); - // serial.writeLine("->red"); - // serial.writeNumber(g); - // serial.writeLine("->green"); - // serial.writeNumber(b); - // serial.writeLine("->blue"); - - if (r > red_wb) - r = red_wb; - if (g > green_wb) - g = green_wb; - if (b > blue_wb) - b = blue_wb; - - r = Math.round(mapRGB(r, 0, red_wb, 0, 255)); - g = Math.round(mapRGB(g, 0, green_wb, 0, 255)); - b = Math.round(mapRGB(b, 0, blue_wb, 0, 255)); - // serial.writeNumber(r); - // serial.writeLine("->rred"); - // serial.writeNumber(g); - // serial.writeLine("->ggreen"); - // serial.writeNumber(b); - // serial.writeLine("->bblue"); - let hsv = rgb2hue(r, g, b); - // serial.writeNumber(hsv); - // serial.writeLine("->hsv"); - let t = startbit_Colors.None; - if (c > 2200 && r > 65 && g > 65 && b > 65) { - t = startbit_Colors.White; - } - else if (c > 800) { - if (hsv < 8 || hsv > 350) - t = startbit_Colors.Red; - else if (hsv > 60 && hsv < 170) { - t = startbit_Colors.Green; - } - else if (hsv > 210 && hsv < 230) { - t = startbit_Colors.Blue; - } - } - else if (c > 200 && r > 10 && g > 7 && b > 7 && r < 16.5 && g < 15 && b < 14) { - t = startbit_Colors.Black; - } - return (color == t); - } + /** + * show a number. + * @param num is a number, eg: 0 + */ + //% weight=91 blockId=startbit_showNumber block="digitaltube show number| %num" + //% subcategory=LED + export function startbit_showNumber(num: number) { + Digitaltube.showNumber(num); + } - /** - * Get the obstacle avoidance sensor status,1 detect obstacle,0 no detect obstacle - */ - //% weight=97 blockId=startbit_avoidSensor block="Obstacle avoidance sensor|detect obstacle" - //% subcategory=Sensor - export function startbit_avoidSensor(): boolean { - let status = 0; - let flag: boolean = false; - - pins.setPull(avoidSensorPin, PinPullMode.PullUp); - status = pins.digitalReadPin(avoidSensorPin); - - if (status == 1) - flag = false; - else - flag = true; - return flag; - } + /** + * show a number in given position. + * @param num number will show, eg: 5 + * @param bit the position of the LED, eg: 0 + */ + //% weight=89 blockId=startbit_showbit block="digitaltube show digit| %num|at %bit" + //% subcategory=LED + export function startbit_showbit(num: number = 5, bit: number = 0) { + Digitaltube.showbit(num, bit); + } + /** + * show a hex number. + * @param num is a hex number, eg: 0 + */ + //% weight=90 blockId=startbit_showhex block="digitaltube show hex number| %num" + //% subcategory=LED + export function startbit_showhex(num: number) { + Digitaltube.showHex(num); + } - /** - * Get the condition of the line follower sensor - */ - //% weight=96 blockId=startbit_readLineFollowerStatus block="Line follower status|%status" - //% subcategory=Sensor - export function startbit_readLineFollowerStatus(status: startbit_lineFollower): boolean { - let s1 = 0; - let s2 = 0; - - s1 = pins.analogReadPin(lineFollowPin1); - s2 = pins.analogReadPin(lineFollowPin2); - s1 = s1 * 255 / 1023; - s2 = s2 * 255 / 1023; - if (s1 < 200) - s1 = 0; - else - s1 = 1; - if (s2 < 200) - s2 = 0; - else - s2 = 1; - - let s = ((1 & s1) << 1) | s2; - if (s == status) { - return true; - } - else { - return false; - } - } + /** + * show or hide dot point. + * @param bit is the position, eg: 1 + * @param show is show/hide dp, eg: true + */ + //% weight=88 blockId=startbit_showDP block="digitaltube DotPoint at| %bit|show %show" + //% subcategory=LED + export function startbit_showDP(bit: number = 1, show: boolean = true) { + Digitaltube.showDP(bit, show); + } - /** - * Get the line follower sensor port ad value - */ - //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="Get line follower sensor|%sensor|ad value" - //% subcategory=Sensor - export function startbit_lineSensorValue(sensor: startbit_LineFollowerSensor): number { - let s1 = 0; - let s2 = 0; - - s1 = pins.analogReadPin(lineFollowPin1); - s2 = pins.analogReadPin(lineFollowPin2); - s1 = s1 * 255 / 1023; - s2 = s2 * 255 / 1023; - - if (sensor == startbit_LineFollowerSensor.LFSensor_1) { - return 255 - s1; - } - else { - return 255 - s2; - } + /** + * set TM1640 intensity, range is [0-8], 0 is off. + * @param val the brightness of the TM1640, eg: 7 + */ + //% weight=92 blockId=startbit_intensity block=" digitaltube set intensity %val" + //% subcategory=LED + export function startbit_intensity(val: number = 7) { + Digitaltube.intensity(val); + } - } - /** - * Get the condition of the touch button,press return 1,or return 0 - */ - //% weight=100 blockId=startbit_touchButton block="Touch button is pressed" - //% subcategory=Sensor - export function startbit_touchButton(): boolean { - let status: boolean = false; - pins.setPull(touchSensorPin, PinPullMode.PullUp); - status = !pins.digitalReadPin(touchSensorPin); - return status; - } + /** + * turn off LED. + */ + //% weight=86 blockId=startbit_off block="turn off digitaltube" + //% subcategory=LED + export function startbit_off() { + Digitaltube.off(); + } - let distanceBak = 0; - /** - * Get the distance of ultrasonic detection to the obstacle - */ - //% weight=90 blockId=startbit_ultrasonic block="Ultrasonic|distance(cm)" - //% subcategory=Sensor - export function startbit_ultrasonic(): number { - pins.setPull(echoPin, PinPullMode.PullNone); - pins.setPull(trigPin, PinPullMode.PullNone); - - pins.digitalWritePin(trigPin, 0); - control.waitMicros(2); - pins.digitalWritePin(trigPin, 1); - control.waitMicros(10); - pins.digitalWritePin(trigPin, 0); - control.waitMicros(5); - let d = pins.pulseIn(echoPin, PulseValue.High, 25000); - let distance = d; - // filter timeout spikes - if (distance == 0 && distanceBak != 0) { - distance = distanceBak; - } - distanceBak = d; - - return Math.round(distance * 10 / 6 / 58 / 1.6); - } + /** + * turn on LED. + */ + //% weight=87 blockId=startbit_on block="turn on digitaltube" + //% subcategory=LED + export function startbit_on() { + Digitaltube.on(); + } - /** - * Get the ad value of the knob moudule - */ - //% weight=92 blockId=startbit_getKnobValue block="Get knob|value(0~255)" - //% subcategory=Sensor - export function startbit_getKnobValue(): number { - let adValue = pins.analogReadPin(knobPin); - adValue = adValue * 255 / 1023; - return adValue; - } - - /** - * Get the ad value of the photosensitive moudule - */ - //% weight=91 blockId=startbit_getphotosensitiveValue block="Get Photosensitive|value(0~255)" - //% subcategory=Sensor - export function startbit_getphotosensitiveValue(): number { - let adValue = pins.analogReadPin(photosensitiveSensorPin1); - adValue = adValue * 255 / 1023; - return 255 - adValue; - } + /** + * clear LED. + */ + //%weight=85 blockId=startbit_clear blockGap=50 block="clear digitaltube" + //% subcategory=LED + export function startbit_clear() { + Digitaltube.clear(); + } + + const APDS9960_I2C_ADDR = 0x39; + const APDS9960_ID_1 = 0xa8; + const APDS9960_ID_2 = 0x9c; + /* APDS-9960 register addresses */ + const APDS9960_ENABLE = 0x80; + const APDS9960_ATIME = 0x81; + const APDS9960_WTIME = 0x83; + const APDS9960_AILTL = 0x84; + const APDS9960_AILTH = 0x85; + const APDS9960_AIHTL = 0x86; + const APDS9960_AIHTH = 0x87; + const APDS9960_PERS = 0x8c; + const APDS9960_CONFIG1 = 0x8d; + const APDS9960_PPULSE = 0x8e; + const APDS9960_CONTROL = 0x8f; + const APDS9960_CONFIG2 = 0x90; + const APDS9960_ID = 0x92; + const APDS9960_STATUS = 0x93; + const APDS9960_CDATAL = 0x94; + const APDS9960_CDATAH = 0x95; + const APDS9960_RDATAL = 0x96; + const APDS9960_RDATAH = 0x97; + const APDS9960_GDATAL = 0x98; + const APDS9960_GDATAH = 0x99; + const APDS9960_BDATAL = 0x9a; + const APDS9960_BDATAH = 0x9b; + const APDS9960_POFFSET_UR = 0x9d; + const APDS9960_POFFSET_DL = 0x9e; + const APDS9960_CONFIG3 = 0x9f; + const APDS9960_GCONF4 = 0xab; + const APDS9960_AICLEAR = 0xe7; + + /* LED Drive values */ + const LED_DRIVE_100MA = 0; + + /* ALS Gain (AGAIN) values */ + const AGAIN_4X = 1; + + /* Default values */ + const DEFAULT_ATIME = 219; // 103ms + const DEFAULT_WTIME = 246; // 27ms + const DEFAULT_PROX_PPULSE = 0x87; // 16us, 8 pulses + const DEFAULT_POFFSET_UR = 0; // 0 offset + const DEFAULT_POFFSET_DL = 0; // 0 offset + const DEFAULT_CONFIG1 = 0x60; // No 12x wait (WTIME) factor + const DEFAULT_AILT = 0xffff; // Force interrupt for calibration + const DEFAULT_AIHT = 0; + const DEFAULT_PERS = 0x11; // 2 consecutive prox or ALS for int. + const DEFAULT_CONFIG2 = 0x01; // No saturation interrupts or LED boost + const DEFAULT_CONFIG3 = 0; // Enable all photodiodes, no SAI + const DEFAULT_LDRIVE = LED_DRIVE_100MA; + const DEFAULT_AGAIN = AGAIN_4X; + + const OFF = 0; + const POWER = 0; + const AMBIENT_LIGHT = 1; + const ALL = 7; + + const red_wb = 2130; + const green_wb = 3500; + const blue_wb = 4620; + + function i2cwrite(reg: number, value: number) { + let buf = pins.createBuffer(2); + buf[0] = reg; + buf[1] = value; + pins.i2cWriteBuffer(APDS9960_I2C_ADDR, buf); + } + + function i2cread(reg: number): number { + pins.i2cWriteNumber(APDS9960_I2C_ADDR, reg, NumberFormat.UInt8BE); + let val = pins.i2cReadNumber(APDS9960_I2C_ADDR, NumberFormat.UInt8BE); + return val; + } + + function InitColor(): boolean { + let id = i2cread(APDS9960_ID); + // serial.writeLine("id:") + // serial.writeNumber(id); + // if (!(id == APDS9960_ID_1 || id == APDS9960_ID_2)) { + // return false; + // } + // serial.writeLine("set mode:") + setMode(ALL, OFF); + i2cwrite(APDS9960_ATIME, DEFAULT_ATIME); + i2cwrite(APDS9960_WTIME, DEFAULT_WTIME); + i2cwrite(APDS9960_PPULSE, DEFAULT_PROX_PPULSE); + i2cwrite(APDS9960_POFFSET_UR, DEFAULT_POFFSET_UR); + i2cwrite(APDS9960_POFFSET_DL, DEFAULT_POFFSET_DL); + i2cwrite(APDS9960_CONFIG1, DEFAULT_CONFIG1); + setLEDDrive(DEFAULT_LDRIVE); + setAmbientLightGain(DEFAULT_AGAIN); + setLightIntLowThreshold(DEFAULT_AILT); + setLightIntHighThreshold(DEFAULT_AIHT); + i2cwrite(APDS9960_PERS, DEFAULT_PERS); + i2cwrite(APDS9960_CONFIG2, DEFAULT_CONFIG2); + i2cwrite(APDS9960_CONFIG3, DEFAULT_CONFIG3); + return true; + } + + function setLEDDrive(drive: number) { + let val = i2cread(APDS9960_CONTROL); + /* Set bits in register to given value */ + drive &= 0b00000011; + drive = drive << 6; + val &= 0b00111111; + val |= drive; + i2cwrite(APDS9960_CONTROL, val); + } + + function setLightIntLowThreshold(threshold: number) { + let val_low = threshold & 0x00ff; + let val_high = (threshold & 0xff00) >> 8; + i2cwrite(APDS9960_AILTL, val_low); + i2cwrite(APDS9960_AILTH, val_high); + } + + function setLightIntHighThreshold(threshold: number) { + let val_low = threshold & 0x00ff; + let val_high = (threshold & 0xff00) >> 8; + i2cwrite(APDS9960_AIHTL, val_low); + i2cwrite(APDS9960_AIHTH, val_high); + } + + function rgb2hue(r: number, g: number, b: number): number { + let max = Math.max(r, Math.max(g, b)); + let min = Math.min(r, Math.min(g, b)); + let c = max - min; + let hue = 0; + let segment = 0; + let shift = 0; + if (c == 0) return 0; + if (r > g && r > b) { + segment = (60.0 * (g - b)) / c; + if (segment < 0) hue = segment + 360; + } else if (g > b && g > r) { + segment = (60.0 * (b - r)) / c; + hue = segment + 120; + } else if (b > g && b > r) { + segment = (60.0 * (r - g)) / c; + hue = segment + 240; + } + return hue; + } + + function setMode(mode: number, enable: number) { + let reg_val = getMode(); + /* Change bit(s) in ENABLE register */ + enable = enable & 0x01; + if (mode >= 0 && mode <= 6) { + if (enable > 0) { + reg_val |= 1 << mode; + } else { + //reg_val &= ~(1 << mode); + reg_val &= 0xff - (1 << mode); + } + } else if (mode == ALL) { + if (enable > 0) { + reg_val = 0x7f; + } else { + reg_val = 0x00; + } + } + i2cwrite(APDS9960_ENABLE, reg_val); + } + + function getMode(): number { + let enable_value = i2cread(APDS9960_ENABLE); + return enable_value; + } + + function enableLightSensor(interrupts: boolean) { + setAmbientLightGain(DEFAULT_AGAIN); + if (interrupts) { + setAmbientLightIntEnable(1); + } else { + setAmbientLightIntEnable(0); + } + enablePower(); + setMode(AMBIENT_LIGHT, 1); + } + + function setAmbientLightGain(drive: number) { + let val = i2cread(APDS9960_CONTROL); + /* Set bits in register to given value */ + drive &= 0b00000011; + val &= 0b11111100; + val |= drive; + i2cwrite(APDS9960_CONTROL, val); + } + + function getAmbientLightGain(): number { + let val = i2cread(APDS9960_CONTROL); + val &= 0b00000011; + return val; + } + + function enablePower() { + setMode(POWER, 1); + } + + function setAmbientLightIntEnable(enable: number) { + let val = i2cread(APDS9960_ENABLE); + /* Set bits in register to given value */ + enable &= 0b00000001; + enable = enable << 4; + val &= 0b11101111; + val |= enable; + i2cwrite(APDS9960_ENABLE, val); + } + + function readAmbientLight(): number { + let val = i2cread(APDS9960_CDATAL); + let val_byte = i2cread(APDS9960_CDATAH); + val = val + val_byte * 256; + return val; + } - /** - * Get the Photosensitive sensor status,1 detect bright,0 no detect bright - */ - //% weight=98 blockId=startbit_photosensitiveSensor block="Photosensitive sensor|detect bright" - //% subcategory=Sensor - export function startbit_photosensitiveSensor(): boolean { - let status = 0; - let flag: boolean = false; - - pins.setPull(photosensitiveSensorPin2, PinPullMode.PullUp); - status = pins.digitalReadPin(photosensitiveSensorPin2); - - if (status == 1) - flag = false; - else - flag = true; - return flag; - } - - /** - * Initialize RGB - */ - function startbit_initRGBLight() { - if (!lhRGBLight) { - lhRGBLight = StartbitRGBLight.create(DigitalPin.P15, 6, StartbitRGBPixelMode.RGB); - } - startbit_clearLight(); - } + /** + * Initialize the color sensor,please execute at boot time + */ + //% weight=88 blockId=startbit_init_colorSensor block="Initialize color sensor port at %port" + export function startbit_init_colorSensor(port: startbit_iic) { + InitColor(); + enableLightSensor(true); + control.waitMicros(100); + } - /** - * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ - //% blockId="startbit_setBrightness" block="set brightness %brightness" - //% weight=100 - //% subcategory=LED - export function startbit_setBrightness(brightness: number): void { - lhRGBLight.setBrightness(brightness); - } + /** + * Color sensor return the color. + */ + //% weight=99 blockId=startbit_checkCurrentColor block="Current color %color" + //% subcategory=Sensor + export function startbit_checkCurrentColor(color: startbit_Colors): boolean { + let c = i2cread(APDS9960_CDATAL) + i2cread(APDS9960_CDATAH) * 256; + let r = i2cread(APDS9960_RDATAL) + i2cread(APDS9960_RDATAH) * 256; + let g = i2cread(APDS9960_GDATAL) + i2cread(APDS9960_GDATAH) * 256; + let b = i2cread(APDS9960_BDATAL) + i2cread(APDS9960_BDATAH) * 256; + + // serial.writeNumber(c); + // serial.writeLine("->ccc"); + // serial.writeNumber(r); + // serial.writeLine("->red"); + // serial.writeNumber(g); + // serial.writeLine("->green"); + // serial.writeNumber(b); + // serial.writeLine("->blue"); + + if (r > red_wb) r = red_wb; + if (g > green_wb) g = green_wb; + if (b > blue_wb) b = blue_wb; + + r = Math.round(mapRGB(r, 0, red_wb, 0, 255)); + g = Math.round(mapRGB(g, 0, green_wb, 0, 255)); + b = Math.round(mapRGB(b, 0, blue_wb, 0, 255)); + // serial.writeNumber(r); + // serial.writeLine("->rred"); + // serial.writeNumber(g); + // serial.writeLine("->ggreen"); + // serial.writeNumber(b); + // serial.writeLine("->bblue"); + let hsv = rgb2hue(r, g, b); + // serial.writeNumber(hsv); + // serial.writeLine("->hsv"); + let t = startbit_Colors.None; + if (c > 2200 && r > 65 && g > 65 && b > 65) { + t = startbit_Colors.White; + } else if (c > 800) { + if (hsv < 8 || hsv > 350) t = startbit_Colors.Red; + else if (hsv > 60 && hsv < 170) { + t = startbit_Colors.Green; + } else if (hsv > 210 && hsv < 230) { + t = startbit_Colors.Blue; + } + } else if ( + c > 200 && + r > 10 && + g > 7 && + b > 7 && + r < 16.5 && + g < 15 && + b < 14 + ) { + t = startbit_Colors.Black; + } + return color == t; + } - /** - * Set the color of the colored lights, after finished the setting please perform the display of colored lights. - */ - //% weight=98 blockId=startbit_setPixelRGB block="Set|%lightoffset|color to %rgb" - //% subcategory=LED - export function startbit_setPixelRGB(lightoffset: StartbitLights, rgb: StartbitRGBColors) { - lhRGBLight.setPixelColor(lightoffset, rgb); - } + /** + * Get the obstacle avoidance sensor status,1 detect obstacle,0 no detect obstacle + */ + //% weight=97 blockId=startbit_avoidSensor block="Obstacle avoidance sensor|detect obstacle" + //% subcategory=Sensor + export function startbit_avoidSensor(): boolean { + let status = 0; + let flag: boolean = false; + + pins.setPull(avoidSensorPin, PinPullMode.PullUp); + status = pins.digitalReadPin(avoidSensorPin); + + if (status == 1) flag = false; + else flag = true; + return flag; + } + /** + * Get the condition of the line follower sensor + */ + //% weight=96 blockId=startbit_readLineFollowerStatus block="Line follower status|%status" + //% subcategory=Sensor + export function startbit_readLineFollowerStatus( + status: startbit_lineFollower + ): boolean { + let s1 = 0; + let s2 = 0; + + s1 = pins.analogReadPin(lineFollowPin1); + s2 = pins.analogReadPin(lineFollowPin2); + s1 = (s1 * 255) / 1023; + s2 = (s2 * 255) / 1023; + if (s1 < 200) s1 = 0; + else s1 = 1; + if (s2 < 200) s2 = 0; + else s2 = 1; + + let s = ((1 & s1) << 1) | s2; + if (s == status) { + return true; + } else { + return false; + } + } - /** - * Set RGB Color argument - */ - //% weight=99 blockId=startbit_setPixelRGBArgs block="Set|%lightoffset|color to %rgb" - //% subcategory=LED - export function startbit_setPixelRGBArgs(lightoffset: StartbitLights, rgb: number) { - lhRGBLight.setPixelColor(lightoffset, rgb); - } + /** + * Get the line follower sensor port ad value + */ + //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="Get line follower sensor|%sensor|ad value" + //% subcategory=Sensor + export function startbit_lineSensorValue( + sensor: startbit_LineFollowerSensor + ): number { + let s1 = 0; + let s2 = 0; + + s1 = pins.analogReadPin(lineFollowPin1); + s2 = pins.analogReadPin(lineFollowPin2); + s1 = (s1 * 255) / 1023; + s2 = (s2 * 255) / 1023; + + if (sensor == startbit_LineFollowerSensor.LFSensor_1) { + return 255 - s1; + } else { + return 255 - s2; + } + } + /** + * Get the condition of the touch button,press return 1,or return 0 + */ + //% weight=100 blockId=startbit_touchButton block="Touch button is pressed" + //% subcategory=Sensor + export function startbit_touchButton(): boolean { + let status: boolean = false; + pins.setPull(touchSensorPin, PinPullMode.PullUp); + status = !pins.digitalReadPin(touchSensorPin); + return status; + } + + let distanceBak = 0; + /** + * Get the distance of ultrasonic detection to the obstacle + */ + //% weight=90 blockId=startbit_ultrasonic block="Ultrasonic|distance(cm)" + //% subcategory=Sensor + export function startbit_ultrasonic(): number { + pins.setPull(echoPin, PinPullMode.PullNone); + pins.setPull(trigPin, PinPullMode.PullNone); + + pins.digitalWritePin(trigPin, 0); + control.waitMicros(2); + pins.digitalWritePin(trigPin, 1); + control.waitMicros(10); + pins.digitalWritePin(trigPin, 0); + control.waitMicros(5); + let d = pins.pulseIn(echoPin, PulseValue.High, 25000); + let distance = d; + // filter timeout spikes + if (distance == 0 && distanceBak != 0) { + distance = distanceBak; + } + distanceBak = d; + + return Math.round((distance * 10) / 6 / 58 / 1.6); + } + /** + * Get the ad value of the knob moudule + */ + //% weight=92 blockId=startbit_getKnobValue block="Get knob|value(0~255)" + //% subcategory=Sensor + export function startbit_getKnobValue(): number { + let adValue = pins.analogReadPin(knobPin); + adValue = (adValue * 255) / 1023; + return adValue; + } - /** - * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. - */ - //% weight=97 blockId=startbit_showLight block="Show light" - //% subcategory=LED - export function startbit_showLight() { - lhRGBLight.show(); - } + /** + * Get the ad value of the photosensitive moudule + */ + //% weight=91 blockId=startbit_getphotosensitiveValue block="Get Photosensitive|value(0~255)" + //% subcategory=Sensor + export function startbit_getphotosensitiveValue(): number { + let adValue = pins.analogReadPin(photosensitiveSensorPin1); + adValue = (adValue * 255) / 1023; + return 255 - adValue; + } - /** - * Clear the color of the colored lights and turn off the lights. - */ - //% weight=96 blockGap=50 blockId=startbit_clearLight block="Clear light" - //% subcategory=LED - export function startbit_clearLight() { - lhRGBLight.clear(); - } + /** + * Get the Photosensitive sensor status,1 detect bright,0 no detect bright + */ + //% weight=98 blockId=startbit_photosensitiveSensor block="Photosensitive sensor|detect bright" + //% subcategory=Sensor + export function startbit_photosensitiveSensor(): boolean { + let status = 0; + let flag: boolean = false; + + pins.setPull(photosensitiveSensorPin2, PinPullMode.PullUp); + status = pins.digitalReadPin(photosensitiveSensorPin2); + + if (status == 1) flag = false; + else flag = true; + return flag; + } - /** - * Initialize Light belt - */ - //% weight=97 blockId=startbit_belt_initRGBLight block="Initialize light belt at port %port" - export function startbit_belt_initRGBLight(port: startbit_ultrasonicPort) { - switch (port) { - case startbit_ultrasonicPort.port1: - if (!lhRGBLightBelt) { - lhRGBLightBelt = StartbitRGBLight.create(DigitalPin.P1, 15, StartbitRGBPixelMode.RGB); - } - break; - case startbit_ultrasonicPort.port2: - if (!lhRGBLightBelt) { - lhRGBLightBelt = StartbitRGBLight.create(DigitalPin.P13, 15, StartbitRGBPixelMode.RGB); - } - break; - } + /** + * Initialize RGB + */ + function startbit_initRGBLight() { + if (!lhRGBLight) { + lhRGBLight = StartbitRGBLight.create( + DigitalPin.P15, + 6, + StartbitRGBPixelMode.RGB + ); + } + startbit_clearLight(); + } - startbit_clearLight(); - } + /** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ + //% blockId="startbit_setBrightness" block="set brightness %brightness" + //% weight=100 + //% subcategory=LED + export function startbit_setBrightness(brightness: number): void { + lhRGBLight.setBrightness(brightness); + } - /** - * Set the color of the colored lights, after finished the setting please perform the display of colored lights. - */ - //% weight=95 blockId=startbit_belt_setPixelRGB block="Set light belt|%lightoffset|color to %rgb" - //% subcategory=LED - export function startbit_belt_setPixelRGB(lightoffset: StartbitLightsBelt, rgb: StartbitRGBColors) { - lhRGBLightBelt.setPixelColor(lightoffset, rgb); - } + /** + * Set the color of the colored lights, after finished the setting please perform the display of colored lights. + */ + //% weight=98 blockId=startbit_setPixelRGB block="Set|%lightoffset|color to %rgb" + //% subcategory=LED + export function startbit_setPixelRGB( + lightoffset: StartbitLights, + rgb: StartbitRGBColors + ) { + lhRGBLight.setPixelColor(lightoffset, rgb); + } - /** - * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. - */ - //% weight=94 blockId=startbit_belt_showLight block="Show light belt" - //% subcategory=LED - export function startbit_belt_showLight() { - lhRGBLightBelt.show(); - } + /** + * Set RGB Color argument + */ + //% weight=99 blockId=startbit_setPixelRGBArgs block="Set|%lightoffset|color to %rgb" + //% subcategory=LED + export function startbit_setPixelRGBArgs( + lightoffset: StartbitLights, + rgb: number + ) { + lhRGBLight.setPixelColor(lightoffset, rgb); + } - /** - * Clear the color of the colored lights and turn off the lights. - */ - //% weight=93 blockGap=50 blockId=startbit_belt_clearLight block="Clear light belt" - //% subcategory=LED - export function startbit_belt_clearLight() { - lhRGBLightBelt.clear(); - } + /** + * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. + */ + //% weight=97 blockId=startbit_showLight block="Show light" + //% subcategory=LED + export function startbit_showLight() { + lhRGBLight.show(); + } - function mapRGB(x: number, in_min: number, in_max: number, out_min: number, out_max: number): number { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; - } + /** + * Clear the color of the colored lights and turn off the lights. + */ + //% weight=96 blockGap=50 blockId=startbit_clearLight block="Clear light" + //% subcategory=LED + export function startbit_clearLight() { + lhRGBLight.clear(); + } - /** - * Resolve the Bluetooth that phone APP send command type, the total of nine types of commands: tank display command, servo debug command, obtaining the distance of ultrasonic command, obtaining temperature command, obtain sound size rank orders, to obtain the light level command, set the color lights command, honking command, firmware version information command. - */ - //% weight=99 blockId=startbit_analyzeBluetoothCmd block="Get bluetooth command type %str" - //% subcategory=Bluetooth - export function startbit_analyzeBluetoothCmd(str: string): number { - if (str.length > 6) { - let cmdHead = str.substr(0, 3); - - if (cmdHead == "CMD") { - let cmdTypeStr: string = str.substr(4, 2); - let cmdType = strToNumber(cmdTypeStr); - if (cmdType > startbit_CmdType.GET_HAND_CMD || cmdType < 0) { - return startbit_CmdType.NO_COMMAND; - } - else { - return cmdType; - } - } - else { - return startbit_CmdType.NO_COMMAND; - } - } - else { - return startbit_CmdType.NO_COMMAND; - } - } - /** - * Resolve the parameters that the phone APP send the command,there are 3 parameters of servo debug command,the other command has just one parameter. - */ - //% weight=98 blockId=startbit_cgetArgs block="Get bluetooth command|%str|argument at %index" - //% index.min=1 index.max=3 - //% subcategory=Bluetooth - export function startbit_getArgs(str: string, index: number): number { - let cmdType = startbit_analyzeBluetoothCmd(str); - if (cmdType == startbit_CmdType.NO_COMMAND) { - return startbit_CarRunCmdType.COMMAND_ERRO; + /** + * Initialize Light belt + */ + //% weight=97 blockId=startbit_belt_initRGBLight block="Initialize light belt at port %port" + export function startbit_belt_initRGBLight(port: startbit_ultrasonicPort) { + switch (port) { + case startbit_ultrasonicPort.port1: + if (!lhRGBLightBelt) { + lhRGBLightBelt = StartbitRGBLight.create( + DigitalPin.P1, + 15, + StartbitRGBPixelMode.RGB + ); } - else { - let dataIndex = 7; - let subLegth = 2; - if (index == 2) { - dataIndex = 10; - subLegth = 2; - } - else if (index == 3) { - dataIndex = 13; - subLegth = 4; - } - if (cmdType == startbit_CmdType.SERVO) { - if (str.length < 17) { - return startbit_CmdType.NO_COMMAND; - } - } - if ((index == 1 && str.length < 10) || (index == 2 && str.length < 13) || (index == 3 && str.length < 17)) { - return 0; - } - let strArgs = str.substr(dataIndex, subLegth); - let arg = strToNumber(strArgs); - if (arg == -1) - return 0; - return arg; + break; + case startbit_ultrasonicPort.port2: + if (!lhRGBLightBelt) { + lhRGBLightBelt = StartbitRGBLight.create( + DigitalPin.P13, + 15, + StartbitRGBPixelMode.RGB + ); } + break; } - /** - * Returns the enumeration of the command type, which can be compared with this module after obtaining the bluetooth command type sent by the mobile phone APP. - */ - //% weight=97 blockId=startbit_getBluetoothCmdtype block="Bluetooth command type %type" - //% subcategory=Bluetooth - export function startbit_getBluetoothCmdtype(type: startbit_CmdType): number { - return type; - } + startbit_clearLight(); + } - /** - * The command type of the tank is stop, go ahead, back, turn left, turn right, slow down, turn left slowly, turn right slowly. - */ - //% weight=96 blockId=startbit_getRunCarType block="Car run type %type" - //% subcategory=Bluetooth - export function startbit_getRunCarType(type: startbit_CarRunCmdType): number { - return type; - } - - /** - * The distance from the ultrasonic obstacle is the standard command, which is sent to the mobile phone. The APP will indicate the distance of the ultrasonic obstacle. - */ - //% weight=95 blockId=startbit_convertUltrasonic block="Convert ultrasonic distance %data" - //% subcategory=Bluetooth - export function startbit_convertUltrasonic(data: number): string { - let cmdStr: string = "CMD|03|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * The conversion temperature value to standard command, sent to the mobile phone, and the APP displays the current temperature. - */ - //% weight=94 blockId=startbit_convertTemperature block="Convert temperature %data" - //% subcategory=Bluetooth - export function startbit_convertTemperature(data: number): string { - let cmdStr: string = "CMD|04|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Convert the light value to the standard command and send it to the mobile phone. The APP displays the current light level (0~255). - */ - //% weight=93 blockId=startbit_convertLight block="Convert light %data" - //% subcategory=Bluetooth - export function startbit_convertLight(data: number): string { - let cmdStr: string = "CMD|06|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Convert the battery value to the standard command and send it to the mobile phone. The APP displays the current voltage. - */ - //% weight=92 blockId=startbit_convertBattery blockGap=50 block="Convert battery %data" - //% subcategory=Bluetooth - export function startbit_convertBattery(data: number): string { - let cmdStr: string = "CMD|07|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } + /** + * Set the color of the colored lights, after finished the setting please perform the display of colored lights. + */ + //% weight=95 blockId=startbit_belt_setPixelRGB block="Set light belt|%lightoffset|color to %rgb" + //% subcategory=LED + export function startbit_belt_setPixelRGB( + lightoffset: StartbitLightsBelt, + rgb: StartbitRGBColors + ) { + lhRGBLightBelt.setPixelColor(lightoffset, rgb); + } - /** - * Convert the hand cmd to phone app - */ - //% weight=51 blockId=startbit_convertHandCmd blockGap=50 block="Convert uHand:bit %data" - export function startbit_convertHandCmd(data: number): string { - let cmdStr: string = "CMD|15|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } + /** + * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. + */ + //% weight=94 blockId=startbit_belt_showLight block="Show light belt" + //% subcategory=LED + export function startbit_belt_showLight() { + lhRGBLightBelt.show(); + } - /** - * Get device mac address - */ - //% weight=100 blockId=startbit_getMacAddress block="Get device id" - //% subcategory=Bluetooth - export function startbit_getMacAddress(): string { - return macStr + "$"; - } - - const ASR_I2C_ADDR = 0x79; - - const ASR_RESULT_ADDR = 100; - const ASR_WORDS_ERASE_ADDR = 101; - const ASR_MODE_ADDR = 102; - const ASR_ADD_WORDS_ADDR = 160; - - export enum ASRMode { - //% block="1" - mode1 = 0x01, - //% block="2" - mode2 = 0x02, - //% block="3" - mode3 = 0x03 - } - - function II2Cread(reg: number): Buffer { - let val = pins.i2cReadBuffer(reg, 1); - return val; - } + /** + * Clear the color of the colored lights and turn off the lights. + */ + //% weight=93 blockGap=50 blockId=startbit_belt_clearLight block="Clear light belt" + //% subcategory=LED + export function startbit_belt_clearLight() { + lhRGBLightBelt.clear(); + } + + function mapRGB( + x: number, + in_min: number, + in_max: number, + out_min: number, + out_max: number + ): number { + return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; + } - function WireWriteByte(addr: number, val: number): boolean { - let buf = pins.createBuffer(1); - buf[0] = val; - let rvalue = pins.i2cWriteBuffer(addr, buf); - if (rvalue != 0) { - return false; - } - return true; - } - - function WireWriteDataArray(addr: number, reg: number, val: number): boolean { - let buf = pins.createBuffer(3); - buf[0] = reg; - buf[1] = val & 0xff; - buf[2] = (val >> 8) & 0xff; - let rvalue = pins.i2cWriteBuffer(addr, buf); - if (rvalue != 0) { - return false; + /** + * Resolve the Bluetooth that phone APP send command type, the total of nine types of commands: tank display command, servo debug command, obtaining the distance of ultrasonic command, obtaining temperature command, obtain sound size rank orders, to obtain the light level command, set the color lights command, honking command, firmware version information command. + */ + //% weight=99 blockId=startbit_analyzeBluetoothCmd block="Get bluetooth command type %str" + //% subcategory=Bluetooth + export function startbit_analyzeBluetoothCmd(str: string): number { + if (str.length > 6) { + let cmdHead = str.substr(0, 3); + + if (cmdHead == "CMD") { + let cmdTypeStr: string = str.substr(4, 2); + let cmdType = strToNumber(cmdTypeStr); + if (cmdType > startbit_CmdType.GET_HAND_CMD || cmdType < 0) { + return startbit_CmdType.NO_COMMAND; + } else { + return cmdType; } - return true; + } else { + return startbit_CmdType.NO_COMMAND; + } + } else { + return startbit_CmdType.NO_COMMAND; } - - function WireReadDataArray(addr: number, reg: number, len: number): number { - if (!WireWriteByte(addr, reg)) { - return -1; + } + /** + * Resolve the parameters that the phone APP send the command,there are 3 parameters of servo debug command,the other command has just one parameter. + */ + //% weight=98 blockId=startbit_cgetArgs block="Get bluetooth command|%str|argument at %index" + //% index.min=1 index.max=3 + //% subcategory=Bluetooth + export function startbit_getArgs(str: string, index: number): number { + let cmdType = startbit_analyzeBluetoothCmd(str); + if (cmdType == startbit_CmdType.NO_COMMAND) { + return startbit_CarRunCmdType.COMMAND_ERRO; + } else { + let dataIndex = 7; + let subLegth = 2; + if (index == 2) { + dataIndex = 10; + subLegth = 2; + } else if (index == 3) { + dataIndex = 13; + subLegth = 4; + } + if (cmdType == startbit_CmdType.SERVO) { + if (str.length < 17) { + return startbit_CmdType.NO_COMMAND; } + } + if ( + (index == 1 && str.length < 10) || + (index == 2 && str.length < 13) || + (index == 3 && str.length < 17) + ) { + return 0; + } + let strArgs = str.substr(dataIndex, subLegth); + let arg = strToNumber(strArgs); + if (arg == -1) return 0; + return arg; + } + } - let buf = II2Cread(addr); - if (buf.length != 1) { - return 0; - } - return buf[0]; - } - - //% weight=85 blockId=startbit_ASRSETMODE block="Set to |%mode mode" - export function startbit_ASRSETMODE(mode: ASRMode) { - WireWriteDataArray(ASR_I2C_ADDR, ASR_MODE_ADDR, mode); - } - - //% weight=84 blockId=startbit_ASRREAD block="Read Data" - //% subcategory=Sensor - export function startbit_ASRREAD(): number { - let val = WireReadDataArray(ASR_I2C_ADDR, ASR_RESULT_ADDR, 1); - return val; - } + /** + * Returns the enumeration of the command type, which can be compared with this module after obtaining the bluetooth command type sent by the mobile phone APP. + */ + //% weight=97 blockId=startbit_getBluetoothCmdtype block="Bluetooth command type %type" + //% subcategory=Bluetooth + export function startbit_getBluetoothCmdtype(type: startbit_CmdType): number { + return type; + } - /** - * @param idNum is a number, eg: 1 - * @param words is text, eg: "ni hao" - */ - //% weight=83 blockId=startbit_ASRAddWords block="Add idNum|%idNum words|%words" - //% subcategory=Sensor - export function startbit_ASRAddWords(idNum: number, words: string) { - let buf = pins.createBuffer(words.length + 2); - buf[0] = ASR_ADD_WORDS_ADDR; - buf[1] = idNum; - for (let i = 0; i < words.length; i++) { - buf[2 + i] = words.charCodeAt(i); - } - pins.i2cWriteBuffer(ASR_I2C_ADDR, buf); - basic.pause(50); - } + /** + * The command type of the tank is stop, go ahead, back, turn left, turn right, slow down, turn left slowly, turn right slowly. + */ + //% weight=96 blockId=startbit_getRunCarType block="Car run type %type" + //% subcategory=Bluetooth + export function startbit_getRunCarType(type: startbit_CarRunCmdType): number { + return type; + } - //% weight=82 blockId=startbit_ASRWORDSERASE block="Erase Data" - //% subcategory=Sensor - export function startbit_ASRWORDSERASE() { - WireWriteDataArray(ASR_I2C_ADDR, ASR_WORDS_ERASE_ADDR, null); - basic.pause(60); - } - - const MP3_I2C_ADDR = 0x7B; - const MP3_PLAY_NUM_ADDR = 1; - const MP3_PLAY_ADDR = 5; - const MP3_PAUSE_ADDR = 6; - const MP3_PREV_ADDR = 8; - const MP3_NEXT_ADDR = 9; - const MP3_VOL_VALUE_ADDR = 12; - const MP3_SINGLE_LOOP_ON_ADDR = 13; - const MP3_SINGLE_LOOP_OFF_ADDR = 14; - - export enum startbit_mp3button { - //% block="PLAY" - PLAY = MP3_PLAY_ADDR, - //% block="PAUSE" - PAUSE = MP3_PAUSE_ADDR, - //% block="PREV" - PREV = MP3_PREV_ADDR, - //% block="NEXT" - NEXT = MP3_NEXT_ADDR - } + /** + * The distance from the ultrasonic obstacle is the standard command, which is sent to the mobile phone. The APP will indicate the distance of the ultrasonic obstacle. + */ + //% weight=95 blockId=startbit_convertUltrasonic block="Convert ultrasonic distance %data" + //% subcategory=Bluetooth + export function startbit_convertUltrasonic(data: number): string { + let cmdStr: string = "CMD|03|"; + cmdStr += data.toString(); + cmdStr += "|$"; + return cmdStr; + } - export enum startbit_mp3Loop { - //% block="ON" - ON = MP3_SINGLE_LOOP_ON_ADDR, - //% block="OFF" - OFF = MP3_SINGLE_LOOP_OFF_ADDR - } + /** + * The conversion temperature value to standard command, sent to the mobile phone, and the APP displays the current temperature. + */ + //% weight=94 blockId=startbit_convertTemperature block="Convert temperature %data" + //% subcategory=Bluetooth + export function startbit_convertTemperature(data: number): string { + let cmdStr: string = "CMD|04|"; + cmdStr += data.toString(); + cmdStr += "|$"; + return cmdStr; + } - //% weight=87 blockId=startbit_MP3_BUTTON block="MP3 |%button music" - //% subcategory=Sensor - export function startbit_MP3_BUTTON(button: startbit_mp3button) { - WireWriteDataArray(MP3_I2C_ADDR, button, null); - basic.pause(20); - } + /** + * Convert the light value to the standard command and send it to the mobile phone. The APP displays the current light level (0~255). + */ + //% weight=93 blockId=startbit_convertLight block="Convert light %data" + //% subcategory=Bluetooth + export function startbit_convertLight(data: number): string { + let cmdStr: string = "CMD|06|"; + cmdStr += data.toString(); + cmdStr += "|$"; + return cmdStr; + } - /** - * @param value is a number, eg: 20 - */ - //% weight=88 blockId=startbit_MP3_VOL block="MP3 VOL |%value" - //% subcategory=Sensor - export function startbit_MP3_VOL(value: number) { - WireWriteDataArray(MP3_I2C_ADDR, MP3_VOL_VALUE_ADDR, value); - basic.pause(20); - } + /** + * Convert the battery value to the standard command and send it to the mobile phone. The APP displays the current voltage. + */ + //% weight=92 blockId=startbit_convertBattery blockGap=50 block="Convert battery %data" + //% subcategory=Bluetooth + export function startbit_convertBattery(data: number): string { + let cmdStr: string = "CMD|07|"; + cmdStr += data.toString(); + cmdStr += "|$"; + return cmdStr; + } + /** + * Convert the hand cmd to phone app + */ + //% weight=51 blockId=startbit_convertHandCmd blockGap=50 block="Convert uHand:bit %data" + export function startbit_convertHandCmd(data: number): string { + let cmdStr: string = "CMD|15|"; + cmdStr += data.toString(); + cmdStr += "|$"; + return cmdStr; + } - //% weight=85 blockId=startbit_MP3_SINGLE_LOOP blockGap=50 block="MP3 SINGLE LOOP |%state" - //% subcategory=Sensor - export function startbit_MP3_SINGLE_LOOP(state: startbit_mp3Loop) { - WireWriteDataArray(MP3_I2C_ADDR, state, null); - basic.pause(20); - } + /** + * Get device mac address + */ + //% weight=100 blockId=startbit_getMacAddress block="Get device id" + //% subcategory=Bluetooth + export function startbit_getMacAddress(): string { + return macStr + "$"; + } + + const ASR_I2C_ADDR = 0x79; + + const ASR_RESULT_ADDR = 100; + const ASR_WORDS_ERASE_ADDR = 101; + const ASR_MODE_ADDR = 102; + const ASR_ADD_WORDS_ADDR = 160; + + export enum ASRMode { + //% block="1" + mode1 = 0x01, + //% block="2" + mode2 = 0x02, + //% block="3" + mode3 = 0x03, + } + + function II2Cread(reg: number): Buffer { + let val = pins.i2cReadBuffer(reg, 1); + return val; + } + + function WireWriteByte(addr: number, val: number): boolean { + let buf = pins.createBuffer(1); + buf[0] = val; + let rvalue = pins.i2cWriteBuffer(addr, buf); + if (rvalue != 0) { + return false; + } + return true; + } + + function WireWriteDataArray(addr: number, reg: number, val: number): boolean { + let buf = pins.createBuffer(3); + buf[0] = reg; + buf[1] = val & 0xff; + buf[2] = (val >> 8) & 0xff; + let rvalue = pins.i2cWriteBuffer(addr, buf); + if (rvalue != 0) { + return false; + } + return true; + } + + function WireReadDataArray(addr: number, reg: number, len: number): number { + if (!WireWriteByte(addr, reg)) { + return -1; + } + + let buf = II2Cread(addr); + if (buf.length != 1) { + return 0; + } + return buf[0]; + } + + //% weight=85 blockId=startbit_ASRSETMODE block="Set to |%mode mode" + export function startbit_ASRSETMODE(mode: ASRMode) { + WireWriteDataArray(ASR_I2C_ADDR, ASR_MODE_ADDR, mode); + } + + //% weight=84 blockId=startbit_ASRREAD block="Read Data" + //% subcategory=Sensor + export function startbit_ASRREAD(): number { + let val = WireReadDataArray(ASR_I2C_ADDR, ASR_RESULT_ADDR, 1); + return val; + } - /** - * @param num is a number, eg: 1 - */ - //% weight=86 blockId=startbit_MP3_PLAY_NUM block="MP3 PLAY NUM|%num" - //% subcategory=Sensor - export function startbit_MP3_PLAY_NUM(num: number) { - WireWriteDataArray(MP3_I2C_ADDR, MP3_PLAY_NUM_ADDR, num); - basic.pause(20); - } + /** + * @param idNum is a number, eg: 1 + * @param words is text, eg: "ni hao" + */ + //% weight=83 blockId=startbit_ASRAddWords block="Add idNum|%idNum words|%words" + //% subcategory=Sensor + export function startbit_ASRAddWords(idNum: number, words: string) { + let buf = pins.createBuffer(words.length + 2); + buf[0] = ASR_ADD_WORDS_ADDR; + buf[1] = idNum; + for (let i = 0; i < words.length; i++) { + buf[2 + i] = words.charCodeAt(i); + } + pins.i2cWriteBuffer(ASR_I2C_ADDR, buf); + basic.pause(50); + } + + //% weight=82 blockId=startbit_ASRWORDSERASE block="Erase Data" + //% subcategory=Sensor + export function startbit_ASRWORDSERASE() { + WireWriteDataArray(ASR_I2C_ADDR, ASR_WORDS_ERASE_ADDR, null); + basic.pause(60); + } + + const MP3_I2C_ADDR = 0x7b; + const MP3_PLAY_NUM_ADDR = 1; + const MP3_PLAY_ADDR = 5; + const MP3_PAUSE_ADDR = 6; + const MP3_PREV_ADDR = 8; + const MP3_NEXT_ADDR = 9; + const MP3_VOL_VALUE_ADDR = 12; + const MP3_SINGLE_LOOP_ON_ADDR = 13; + const MP3_SINGLE_LOOP_OFF_ADDR = 14; + + export enum startbit_mp3button { + //% block="PLAY" + PLAY = MP3_PLAY_ADDR, + //% block="PAUSE" + PAUSE = MP3_PAUSE_ADDR, + //% block="PREV" + PREV = MP3_PREV_ADDR, + //% block="NEXT" + NEXT = MP3_NEXT_ADDR, + } + + export enum startbit_mp3Loop { + //% block="ON" + ON = MP3_SINGLE_LOOP_ON_ADDR, + //% block="OFF" + OFF = MP3_SINGLE_LOOP_OFF_ADDR, + } + + //% weight=87 blockId=startbit_MP3_BUTTON block="MP3 |%button music" + //% subcategory=Sensor + export function startbit_MP3_BUTTON(button: startbit_mp3button) { + WireWriteDataArray(MP3_I2C_ADDR, button, null); + basic.pause(20); + } - export enum startbit_LineFollowerSensors { - //% block="S1" - S1, - //% block="S2" - S2, - //% block="S3" - S3, - //% block="S4" - S4 - } + /** + * @param value is a number, eg: 20 + */ + //% weight=88 blockId=startbit_MP3_VOL block="MP3 VOL |%value" + //% subcategory=Sensor + export function startbit_MP3_VOL(value: number) { + WireWriteDataArray(MP3_I2C_ADDR, MP3_VOL_VALUE_ADDR, value); + basic.pause(20); + } + + //% weight=85 blockId=startbit_MP3_SINGLE_LOOP blockGap=50 block="MP3 SINGLE LOOP |%state" + //% subcategory=Sensor + export function startbit_MP3_SINGLE_LOOP(state: startbit_mp3Loop) { + WireWriteDataArray(MP3_I2C_ADDR, state, null); + basic.pause(20); + } - export enum startbit_LineColor { - //% block="Black" - Black, - //% block="White" - White - } - - const LINE_FOLLOWER_I2C_ADDR = 0x78 - - //% weight=95 blockId=startbit_line_followers blockGap=50 block="Line follower %lineFollowerSensor in %LineColor ?" - //% inlineInputMode=inline - //% subcategory=Sensor - export function startbit_line_followers(lineFollowerSensor: startbit_LineFollowerSensors, LineColor: startbit_LineColor): boolean { - pins.i2cWriteNumber(LINE_FOLLOWER_I2C_ADDR, 1, NumberFormat.UInt8BE); - let data = pins.i2cReadNumber(LINE_FOLLOWER_I2C_ADDR, NumberFormat.UInt8BE); - let status = false; - switch (lineFollowerSensor) { - case startbit_LineFollowerSensors.S1: - if (data & 0x01) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } - else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S2: - if (data & 0x02) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } - else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S3: - if (data & 0x04) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } - else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S4: - if (data & 0x08) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } - else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; + /** + * @param num is a number, eg: 1 + */ + //% weight=86 blockId=startbit_MP3_PLAY_NUM block="MP3 PLAY NUM|%num" + //% subcategory=Sensor + export function startbit_MP3_PLAY_NUM(num: number) { + WireWriteDataArray(MP3_I2C_ADDR, MP3_PLAY_NUM_ADDR, num); + basic.pause(20); + } + + export enum startbit_LineFollowerSensors { + //% block="S1" + S1, + //% block="S2" + S2, + //% block="S3" + S3, + //% block="S4" + S4, + } + + export enum startbit_LineColor { + //% block="Black" + Black, + //% block="White" + White, + } + + const LINE_FOLLOWER_I2C_ADDR = 0x78; + + //% weight=95 blockId=startbit_line_followers blockGap=50 block="Line follower %lineFollowerSensor in %LineColor ?" + //% inlineInputMode=inline + //% subcategory=Sensor + export function startbit_line_followers( + lineFollowerSensor: startbit_LineFollowerSensors, + LineColor: startbit_LineColor + ): boolean { + pins.i2cWriteNumber(LINE_FOLLOWER_I2C_ADDR, 1, NumberFormat.UInt8BE); + let data = pins.i2cReadNumber(LINE_FOLLOWER_I2C_ADDR, NumberFormat.UInt8BE); + let status = false; + switch (lineFollowerSensor) { + case startbit_LineFollowerSensors.S1: + if (data & 0x01) { + if (LineColor == startbit_LineColor.Black) { + status = true; + } + } else { + if (LineColor == startbit_LineColor.White) { + status = true; + } + } + break; + + case startbit_LineFollowerSensors.S2: + if (data & 0x02) { + if (LineColor == startbit_LineColor.Black) { + status = true; + } + } else { + if (LineColor == startbit_LineColor.White) { + status = true; + } + } + break; + + case startbit_LineFollowerSensors.S3: + if (data & 0x04) { + if (LineColor == startbit_LineColor.Black) { + status = true; + } + } else { + if (LineColor == startbit_LineColor.White) { + status = true; + } + } + break; + + case startbit_LineFollowerSensors.S4: + if (data & 0x08) { + if (LineColor == startbit_LineColor.Black) { + status = true; + } + } else { + if (LineColor == startbit_LineColor.White) { + status = true; + } } - return status; + break; } + return status; + } } From d754454f2cec592a38df053cd59ff708a7e2bad4 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 09:58:19 +0100 Subject: [PATCH 002/253] Edited Readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a31ec8f..e4f2c2f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ -# StartbitV2 - The block for microbit v2 +# Informatiktheater + +Adapted code blocks for Hiwonder extension board based on [StartbitV2](https://github.com/Hiwonder/StartbitV2). +Some blocks were removed and the remaining ones translated into German. +A few new blocks were added to communicate with the attached hardware (e.g. mp3player). From 18940eb55c995e7d788fec26094cb10eb5c90084 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 16:11:14 +0100 Subject: [PATCH 003/253] Removed more blocks and added translations --- StartbitV2.ts | 894 ++------------------------------------------------ 1 file changed, 21 insertions(+), 873 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ddcdcb2..dadeaf6 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -45,7 +45,7 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="Initialize ultrasonic|port %port" + //% weight=91 blockId=ultrasonic_init block="Initialisiere Ultraschall|port %port" export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -67,17 +67,6 @@ namespace Informatiktheater { } let touchSensorPin: DigitalPin; - //% weight=93 blockId=touchSensor_init block="Initialize touchSensor|port %port" - export function touchSensor_init(port: startbit_touchKeyPort) { - switch (port) { - case startbit_touchKeyPort.port1: - touchSensorPin = DigitalPin.P1; - break; - case startbit_touchKeyPort.port2: - touchSensorPin = DigitalPin.P13; - break; - } - } export enum startbit_lineFollowPort { //% block="Port 1" @@ -86,7 +75,7 @@ namespace Informatiktheater { let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="Initialize lineFollowSensor|port %port" + //% weight=92 blockId=lineFollowSensor_init block="Initialisiere Linienfolger-Sensor|port %port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -97,9 +86,9 @@ namespace Informatiktheater { } export enum startbit_PinIOStatus { - //% block="Low" + //% block="Aus" Low = 0x00, - //% block="High" + //% block="Ein" Hight = 0x01, } @@ -121,7 +110,7 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="Initialize knobSensor|port %port" + //% weight=99 blockId=knobSensor_init block="Initialisiere Dreh-Sensor|port %port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -140,20 +129,6 @@ namespace Informatiktheater { port1 = 0x00, } - let photosensitiveSensorPin1: AnalogPin; - let photosensitiveSensorPin2: DigitalPin; - //% weight=95 blockId=photosensitiveSensor_init block="Initialize photosensitiveSensor|port %port" - export function photosensitiveSensor_init( - port: startbit_PhotosensitiveSensor - ) { - switch (port) { - case startbit_PhotosensitiveSensor.port1: - photosensitiveSensorPin1 = AnalogPin.P1; - photosensitiveSensorPin2 = DigitalPin.P2; - break; - } - } - export enum startbit_fanPort { //% block="Port 1" port1, @@ -161,21 +136,6 @@ namespace Informatiktheater { port2, } - let fanPin1: AnalogPin; - let fanPin2: AnalogPin; - export function fanSensor_init(port: startbit_fanPort) { - switch (port) { - case startbit_fanPort.port1: - fanPin1 = AnalogPin.P1; - fanPin2 = AnalogPin.P2; - break; - case startbit_fanPort.port2: - fanPin1 = AnalogPin.P13; - fanPin2 = AnalogPin.P14; - break; - } - } - export enum startbit_iic { //% block="Port 3" port3 = 0x03, @@ -184,31 +144,8 @@ namespace Informatiktheater { //% block="Port 6" port6 = 0x06, } - //% weight=89 blockId=MP3_init block="Initialize MP3Module|port %port" - export function MP3_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } - - //% weight=87 blockId=ASR_init block="Initialize ASRModule|port %port" - export function ASR_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } - //% weight=86 blockId=lineFollow_iic_init block="Initialize lineFollow iic|port %port" + //% weight=86 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: @@ -220,19 +157,6 @@ namespace Informatiktheater { } } - let avoidSensorPin: DigitalPin; - //% weight=96 blockId=avoidSensor_init block="Initialize avoidSensor|port %port" - export function avoidSensor_init(port: startbit_touchKeyPort) { - switch (port) { - case startbit_touchKeyPort.port1: - avoidSensorPin = DigitalPin.P1; - break; - case startbit_touchKeyPort.port2: - avoidSensorPin = DigitalPin.P13; - break; - } - } - export enum startbit_servorange { //% block="180" range1 = 180, @@ -240,73 +164,10 @@ namespace Informatiktheater { range2 = 270, } - export enum startbit_digitaltubePort { - //% block="Port 1" - port1 = 0x01, - //% block="Port 2" - port2 = 0x02, - } - - export enum startbit_CmdType { - //% block="Invalid command" - NO_COMMAND = 0, - //% block="car run" - CAR_RUN = 1, - //% block="robot run" - ROBOT_RUN = 1, - //% block="Servo" - SERVO = 2, - //% block="Ultrasonic distance" - ULTRASONIC = 3, - //% block="Temperature" - TEMPERATURE = 4, - //% block="Light" - LIGHT = 6, - //% block="Voltage" - BAT = 7, - //% block="Rgb light" - RGB_LIGHT = 8, - //% block="Honk horn" - DIDI = 9, - //% block="Read firmware version" - VERSION = 10, - //% block="Read angle" - READ_ANGLE = 11, - //% block="Light belt" - RGB_BELT = 12, - //% block="WIFI mode" - WIFI_MODE = 13, - //% block="Get mac" - GET_MAC = 14, - //% block="Get hand cmd" - GET_HAND_CMD = 15, - } - - export enum startbit_CarRunCmdType { - //% block="Stop" - STOP = 0, - //% block="Go ahead" - GO_AHEAD, - //% block="Back" - GO_BACK, - //% block="Turn left" - TURN_LEFT, - //% block="Turn right" - TURN_RIGHT, - //% block="Go ahead slowly" - GO_AHEAD_SLOW, - //% block="Turn left slowly" - TURN_LEFT_SLOW, - //% block="Turn right slowly" - TURN_RIGHT_SLOW, - //% block="Invalid command" - COMMAND_ERRO, - } - /** * Startbit initialization, please execute at boot time */ - //% weight=100 blockId=startbit_Init block="Initialize StartbitV2" + //% weight=100 blockId=startbit_Init block="Initialisiere Informatiktheater" export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -496,7 +357,7 @@ namespace Informatiktheater { /** * Set the angle of servo 1 to 8, range of 0~270 degree */ - //% weight=100 blockId=setServo block="Set pwm servo range %range|index %index|angle %angle|duration %duration" + //% weight=100 blockId=setServo block="Setze PWM Servo Distanz %range|Index %index|Winkel %angle|Dauer %duration" //% angle.min=0 angle.max=270 //% inlineInputMode=inline //% subcategory=Servo/Motor @@ -523,157 +384,10 @@ namespace Informatiktheater { basic.pause(1); } - /** - * Set the angle of bus_servo, range:0~240 - */ - //% weight=98 blockId=setBusServo blockGap=50 block="Set bus servo index %index|angle %angle|duration %duration" - //% angle.min=0 angle.max=240 - //% inlineInputMode=inline - //% subcategory=Servo/Motor - export function setBusServo( - index: number = 1, - angle: number = 135, - duration: number = 500 - ) { - let position = mapRGB(angle, 0, 240, 0, 1000); - - let buf = pins.createBuffer(10); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x08; - buf[3] = 0x35; //cmd type - buf[4] = 0x01; - buf[5] = duration & 0xff; - buf[6] = (duration >> 8) & 0xff; - buf[7] = index; - buf[8] = position & 0xff; - buf[9] = (position >> 8) & 0xff; - serial.writeBuffer(buf); - basic.pause(1); - } - - /** - * Set the servo controller to run a actiongroup - * @param times Running times. eg: 1 - */ - //% weight=94 blockId=startbit_runActionGroup block="Run ActionGroup|index %index|times %times" - //% subcategory=Servo/Motor - export function startbit_runActionGroup(index: number, times: number = 1) { - let buf = pins.createBuffer(7); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x05; - buf[3] = 0x06; //cmd type CMD_ACTION_GROUP_RUN - buf[4] = index & 0xff; - buf[5] = times & 0xff; - buf[6] = (times >> 8) & 0xff; - - actiongroup_finished = false; - serial.writeBuffer(buf); - } - - /** - * Stop running actiongroup - */ - //% weight=92 blockId=startbit_stopnActionGroup block="Stop ActionGroup" - //% subcategory=Servo/Motor - export function startbit_stopActionGroup() { - let buf = pins.createBuffer(7); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x02; - buf[3] = 0x07; //cmd type CMD_ACTION_GROUP_STOP - - actiongroup_finished = false; - serial.writeBuffer(buf); - } - - /** - * Wait for Actiongroup Finishing - */ - //% weight=93 blockId=startbit_actionRunover block="Action run over" - //% subcategory=Servo/Motor - export function startbit_actionRunover(): boolean { - // let ret = false; - if (actiongroup_finished == true) { - // ret = true; - actiongroup_finished = true; - } else { - actiongroup_finished = false; - } - return actiongroup_finished; - } - - // /** - // * Send read startbit servos angle command - // */ - // //% weight=99 blockId=startbit_readAngle block="Send |%servo|angle command " - // //% subcategory=Servo/Motor - // export function startbit_readAngle(servo: startbit_Servos) { - // let buf = pins.createBuffer(6); - // buf[0] = 0x55; - // buf[1] = 0x55; - // buf[2] = 0x04; - // buf[3] = 0x3E;//cmd type - // buf[4] = 0x05; - // buf[5] = servo; - // serial.writeBuffer(buf); - // } - - // /** - // * Do someting when Startbit receive angle - // * @param body code to run when event is raised - // */ - // //% weight=97 blockId=onStartbit_getAngle blockGap=50 block="on Startbit|%servo|get angle" - // //% subcategory=Servo/Motor - // export function onStartbit_getAngle(servo: startbit_Servos, body: Action) { - // control.onEvent(MESSAGE_ANGLE, servo, body); - // } - - // /** - // * Get servos angle - // */ - // //% weight=98 blockId=getServosAngle block="Get|%servo|angle(-120~120)" - // //% subcategory=Servo/Motor - // export function getServosAngle(servo: startbit_Servos): number { - // if (servo == startbit_Servos.Servo1) { - // return servo1Angle; - // } - // else if (servo == startbit_Servos.Servo2) { - // return servo2Angle; - // } - // else - // return 0xFFF; - // } - - /** - * Send robot attitude to the servo controller - * @param pitch eg: 0 - * @param roll eg: 0 - */ - //% weight=91 blockId=startbit_sendAttitude block="Send pitch|%pitch|and roll|%roll" - /* - export function startbit_sendAttitude(pitch: number, roll: number) { - pitch < -90 ? -90 : pitch; - pitch > 90 ? 90 : pitch; - roll < -90 ? -90 : roll; - roll > 90 ? 90 : roll; - - let buf = pins.createBuffer(6); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x04; - buf[3] = 0x5A; - buf[4] = pitch; - buf[5] = roll; - serial.writeBuffer(buf); - } - */ - /** * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. */ - //% weight=96 blockId=startbit_setMotorSpeed block="Set motor1 speed(-100~100)|%speed1|and motor2|speed %speed2" + //% weight=96 blockId=startbit_setMotorSpeed block="Setze Motor1 Geschwindigkeit(-100 bis +100)|%speed1|und Motor2|Geschwindigkeit %speed2" //% speed1.min=-100 speed1.max=100 //% speed2.min=-100 speed2.max=100 //% subcategory=Servo/Motor @@ -693,38 +407,6 @@ namespace Informatiktheater { serial.writeBuffer(buf); } - /** - * Set the speed of the fan, range of -100~100. - */ - //% weight=95 blockId=startbit_setFanSpeed blockGap=50 block="Set fan speed(-100~100)|%speed1" - //% speed1.min=-100 speed1.max=100 - //% subcategory=Servo/Motor - export function startbit_setFanSpeed(speed1: number) { - if (speed1 > 100 || speed1 < -100) { - return; - } - - if (speed1 < 0) { - pins.analogWritePin(fanPin2, 0); - pins.analogWritePin(fanPin1, pins.map(-speed1, 0, 100, 0, 1023)); - } else if (speed1 > 0) { - pins.analogWritePin(fanPin1, 0); - pins.analogWritePin(fanPin2, pins.map(speed1, 0, 100, 0, 1023)); - } else { - pins.analogWritePin(fanPin2, 0); - pins.analogWritePin(fanPin1, 0); - } - } - - /** - * Get startbit current voltage,the unit is mV - */ - //% weight=93 blockGap=50 blockId=startbit_getBatVoltage block="Get startbit current voltage (mV)" - //% subcategory=Sensor - export function startbit_getBatVoltage(): number { - return currentVoltage; - } - /** * TM1640 LED display */ @@ -869,130 +551,6 @@ namespace Informatiktheater { this._write_dsp_ctrl(); } } - /** - * 创建 TM1640 对象. - * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 - * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 - * @param intensity the brightness of the LED, eg: 7 - * @param count the count of the LED, eg: 4 - */ - function startbit_TM1640create( - port: startbit_digitaltubePort, - intensity: number, - count: number - ): startbit_TM1640LEDs { - let digitaltube = new startbit_TM1640LEDs(); - switch (port) { - case startbit_digitaltubePort.port1: - digitaltube.clk = DigitalPin.P2; - digitaltube.dio = DigitalPin.P1; - break; - case startbit_digitaltubePort.port2: - digitaltube.clk = DigitalPin.P14; - digitaltube.dio = DigitalPin.P13; - break; - } - - if (count < 1 || count > 5) count = 4; - digitaltube.count = count; - digitaltube.brightness = intensity; - digitaltube.init(); - return digitaltube; - } - - /** - * @param clk the CLK pin for TM1640, eg: DigitalPin.P1 - * @param dio the DIO pin for TM1640, eg: DigitalPin.P2 - * @param intensity the brightness of the LED, eg: 7 - * @param count the count of the LED, eg: 4 - */ - //% weight=90 blockId=startbit_digitaltube blockGap=50 block="digitaltube|%port|intensity %intensity|LED count %count" - export function startbit_digitaltube( - port: startbit_digitaltubePort, - intensity: number, - count: number - ) { - Digitaltube = startbit_TM1640create(port, intensity, count); - } - - /** - * show a number. - * @param num is a number, eg: 0 - */ - //% weight=91 blockId=startbit_showNumber block="digitaltube show number| %num" - //% subcategory=LED - export function startbit_showNumber(num: number) { - Digitaltube.showNumber(num); - } - - /** - * show a number in given position. - * @param num number will show, eg: 5 - * @param bit the position of the LED, eg: 0 - */ - //% weight=89 blockId=startbit_showbit block="digitaltube show digit| %num|at %bit" - //% subcategory=LED - export function startbit_showbit(num: number = 5, bit: number = 0) { - Digitaltube.showbit(num, bit); - } - - /** - * show a hex number. - * @param num is a hex number, eg: 0 - */ - //% weight=90 blockId=startbit_showhex block="digitaltube show hex number| %num" - //% subcategory=LED - export function startbit_showhex(num: number) { - Digitaltube.showHex(num); - } - - /** - * show or hide dot point. - * @param bit is the position, eg: 1 - * @param show is show/hide dp, eg: true - */ - //% weight=88 blockId=startbit_showDP block="digitaltube DotPoint at| %bit|show %show" - //% subcategory=LED - export function startbit_showDP(bit: number = 1, show: boolean = true) { - Digitaltube.showDP(bit, show); - } - - /** - * set TM1640 intensity, range is [0-8], 0 is off. - * @param val the brightness of the TM1640, eg: 7 - */ - //% weight=92 blockId=startbit_intensity block=" digitaltube set intensity %val" - //% subcategory=LED - export function startbit_intensity(val: number = 7) { - Digitaltube.intensity(val); - } - - /** - * turn off LED. - */ - //% weight=86 blockId=startbit_off block="turn off digitaltube" - //% subcategory=LED - export function startbit_off() { - Digitaltube.off(); - } - - /** - * turn on LED. - */ - //% weight=87 blockId=startbit_on block="turn on digitaltube" - //% subcategory=LED - export function startbit_on() { - Digitaltube.on(); - } - - /** - * clear LED. - */ - //%weight=85 blockId=startbit_clear blockGap=50 block="clear digitaltube" - //% subcategory=LED - export function startbit_clear() { - Digitaltube.clear(); - } const APDS9960_I2C_ADDR = 0x39; const APDS9960_ID_1 = 0xa8; @@ -1212,97 +770,10 @@ namespace Informatiktheater { return val; } - /** - * Initialize the color sensor,please execute at boot time - */ - //% weight=88 blockId=startbit_init_colorSensor block="Initialize color sensor port at %port" - export function startbit_init_colorSensor(port: startbit_iic) { - InitColor(); - enableLightSensor(true); - control.waitMicros(100); - } - - /** - * Color sensor return the color. - */ - //% weight=99 blockId=startbit_checkCurrentColor block="Current color %color" - //% subcategory=Sensor - export function startbit_checkCurrentColor(color: startbit_Colors): boolean { - let c = i2cread(APDS9960_CDATAL) + i2cread(APDS9960_CDATAH) * 256; - let r = i2cread(APDS9960_RDATAL) + i2cread(APDS9960_RDATAH) * 256; - let g = i2cread(APDS9960_GDATAL) + i2cread(APDS9960_GDATAH) * 256; - let b = i2cread(APDS9960_BDATAL) + i2cread(APDS9960_BDATAH) * 256; - - // serial.writeNumber(c); - // serial.writeLine("->ccc"); - // serial.writeNumber(r); - // serial.writeLine("->red"); - // serial.writeNumber(g); - // serial.writeLine("->green"); - // serial.writeNumber(b); - // serial.writeLine("->blue"); - - if (r > red_wb) r = red_wb; - if (g > green_wb) g = green_wb; - if (b > blue_wb) b = blue_wb; - - r = Math.round(mapRGB(r, 0, red_wb, 0, 255)); - g = Math.round(mapRGB(g, 0, green_wb, 0, 255)); - b = Math.round(mapRGB(b, 0, blue_wb, 0, 255)); - // serial.writeNumber(r); - // serial.writeLine("->rred"); - // serial.writeNumber(g); - // serial.writeLine("->ggreen"); - // serial.writeNumber(b); - // serial.writeLine("->bblue"); - let hsv = rgb2hue(r, g, b); - // serial.writeNumber(hsv); - // serial.writeLine("->hsv"); - let t = startbit_Colors.None; - if (c > 2200 && r > 65 && g > 65 && b > 65) { - t = startbit_Colors.White; - } else if (c > 800) { - if (hsv < 8 || hsv > 350) t = startbit_Colors.Red; - else if (hsv > 60 && hsv < 170) { - t = startbit_Colors.Green; - } else if (hsv > 210 && hsv < 230) { - t = startbit_Colors.Blue; - } - } else if ( - c > 200 && - r > 10 && - g > 7 && - b > 7 && - r < 16.5 && - g < 15 && - b < 14 - ) { - t = startbit_Colors.Black; - } - return color == t; - } - - /** - * Get the obstacle avoidance sensor status,1 detect obstacle,0 no detect obstacle - */ - //% weight=97 blockId=startbit_avoidSensor block="Obstacle avoidance sensor|detect obstacle" - //% subcategory=Sensor - export function startbit_avoidSensor(): boolean { - let status = 0; - let flag: boolean = false; - - pins.setPull(avoidSensorPin, PinPullMode.PullUp); - status = pins.digitalReadPin(avoidSensorPin); - - if (status == 1) flag = false; - else flag = true; - return flag; - } - /** * Get the condition of the line follower sensor */ - //% weight=96 blockId=startbit_readLineFollowerStatus block="Line follower status|%status" + //% weight=96 blockId=startbit_readLineFollowerStatus block="Linenfolger Status|%status" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower @@ -1330,7 +801,7 @@ namespace Informatiktheater { /** * Get the line follower sensor port ad value */ - //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="Get line follower sensor|%sensor|ad value" + //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="Hole Linienfolger Sensor|%sensor|ad Wert" //% subcategory=Sensor export function startbit_lineSensorValue( sensor: startbit_LineFollowerSensor @@ -1349,23 +820,12 @@ namespace Informatiktheater { return 255 - s2; } } - /** - * Get the condition of the touch button,press return 1,or return 0 - */ - //% weight=100 blockId=startbit_touchButton block="Touch button is pressed" - //% subcategory=Sensor - export function startbit_touchButton(): boolean { - let status: boolean = false; - pins.setPull(touchSensorPin, PinPullMode.PullUp); - status = !pins.digitalReadPin(touchSensorPin); - return status; - } let distanceBak = 0; /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=90 blockId=startbit_ultrasonic block="Ultrasonic|distance(cm)" + //% weight=90 blockId=startbit_ultrasonic block="Ultraschall|Distanz (cm)" //% subcategory=Sensor export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); @@ -1391,7 +851,7 @@ namespace Informatiktheater { /** * Get the ad value of the knob moudule */ - //% weight=92 blockId=startbit_getKnobValue block="Get knob|value(0~255)" + //% weight=92 blockId=startbit_getKnobValue block="Hole Dreh-Sensor|Wert (0~255)" //% subcategory=Sensor export function startbit_getKnobValue(): number { let adValue = pins.analogReadPin(knobPin); @@ -1399,34 +859,6 @@ namespace Informatiktheater { return adValue; } - /** - * Get the ad value of the photosensitive moudule - */ - //% weight=91 blockId=startbit_getphotosensitiveValue block="Get Photosensitive|value(0~255)" - //% subcategory=Sensor - export function startbit_getphotosensitiveValue(): number { - let adValue = pins.analogReadPin(photosensitiveSensorPin1); - adValue = (adValue * 255) / 1023; - return 255 - adValue; - } - - /** - * Get the Photosensitive sensor status,1 detect bright,0 no detect bright - */ - //% weight=98 blockId=startbit_photosensitiveSensor block="Photosensitive sensor|detect bright" - //% subcategory=Sensor - export function startbit_photosensitiveSensor(): boolean { - let status = 0; - let flag: boolean = false; - - pins.setPull(photosensitiveSensorPin2, PinPullMode.PullUp); - status = pins.digitalReadPin(photosensitiveSensorPin2); - - if (status == 1) flag = false; - else flag = true; - return flag; - } - /** * Initialize RGB */ @@ -1445,29 +877,17 @@ namespace Informatiktheater { * Set the brightness of the strip. This flag only applies to future operation. * @param brightness a measure of LED brightness in 0-255. eg: 255 */ - //% blockId="startbit_setBrightness" block="set brightness %brightness" + //% blockId="startbit_setBrightness" block="Setze Helligkeit %brightness" //% weight=100 //% subcategory=LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); } - /** - * Set the color of the colored lights, after finished the setting please perform the display of colored lights. - */ - //% weight=98 blockId=startbit_setPixelRGB block="Set|%lightoffset|color to %rgb" - //% subcategory=LED - export function startbit_setPixelRGB( - lightoffset: StartbitLights, - rgb: StartbitRGBColors - ) { - lhRGBLight.setPixelColor(lightoffset, rgb); - } - /** * Set RGB Color argument */ - //% weight=99 blockId=startbit_setPixelRGBArgs block="Set|%lightoffset|color to %rgb" + //% weight=99 blockId=startbit_setPixelRGBArgs block="Setze|%lightoffset|Farbe auf %rgb" //% subcategory=LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, @@ -1479,7 +899,7 @@ namespace Informatiktheater { /** * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. */ - //% weight=97 blockId=startbit_showLight block="Show light" + //% weight=97 blockId=startbit_showLight block="Licht an" //% subcategory=LED export function startbit_showLight() { lhRGBLight.show(); @@ -1488,71 +908,12 @@ namespace Informatiktheater { /** * Clear the color of the colored lights and turn off the lights. */ - //% weight=96 blockGap=50 blockId=startbit_clearLight block="Clear light" + //% weight=96 blockGap=50 blockId=startbit_clearLight block="Licht aus" //% subcategory=LED export function startbit_clearLight() { lhRGBLight.clear(); } - /** - * Initialize Light belt - */ - //% weight=97 blockId=startbit_belt_initRGBLight block="Initialize light belt at port %port" - export function startbit_belt_initRGBLight(port: startbit_ultrasonicPort) { - switch (port) { - case startbit_ultrasonicPort.port1: - if (!lhRGBLightBelt) { - lhRGBLightBelt = StartbitRGBLight.create( - DigitalPin.P1, - 15, - StartbitRGBPixelMode.RGB - ); - } - break; - case startbit_ultrasonicPort.port2: - if (!lhRGBLightBelt) { - lhRGBLightBelt = StartbitRGBLight.create( - DigitalPin.P13, - 15, - StartbitRGBPixelMode.RGB - ); - } - break; - } - - startbit_clearLight(); - } - - /** - * Set the color of the colored lights, after finished the setting please perform the display of colored lights. - */ - //% weight=95 blockId=startbit_belt_setPixelRGB block="Set light belt|%lightoffset|color to %rgb" - //% subcategory=LED - export function startbit_belt_setPixelRGB( - lightoffset: StartbitLightsBelt, - rgb: StartbitRGBColors - ) { - lhRGBLightBelt.setPixelColor(lightoffset, rgb); - } - - /** - * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. - */ - //% weight=94 blockId=startbit_belt_showLight block="Show light belt" - //% subcategory=LED - export function startbit_belt_showLight() { - lhRGBLightBelt.show(); - } - - /** - * Clear the color of the colored lights and turn off the lights. - */ - //% weight=93 blockGap=50 blockId=startbit_belt_clearLight block="Clear light belt" - //% subcategory=LED - export function startbit_belt_clearLight() { - lhRGBLightBelt.clear(); - } - function mapRGB( x: number, in_min: number, @@ -1563,155 +924,6 @@ namespace Informatiktheater { return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; } - /** - * Resolve the Bluetooth that phone APP send command type, the total of nine types of commands: tank display command, servo debug command, obtaining the distance of ultrasonic command, obtaining temperature command, obtain sound size rank orders, to obtain the light level command, set the color lights command, honking command, firmware version information command. - */ - //% weight=99 blockId=startbit_analyzeBluetoothCmd block="Get bluetooth command type %str" - //% subcategory=Bluetooth - export function startbit_analyzeBluetoothCmd(str: string): number { - if (str.length > 6) { - let cmdHead = str.substr(0, 3); - - if (cmdHead == "CMD") { - let cmdTypeStr: string = str.substr(4, 2); - let cmdType = strToNumber(cmdTypeStr); - if (cmdType > startbit_CmdType.GET_HAND_CMD || cmdType < 0) { - return startbit_CmdType.NO_COMMAND; - } else { - return cmdType; - } - } else { - return startbit_CmdType.NO_COMMAND; - } - } else { - return startbit_CmdType.NO_COMMAND; - } - } - /** - * Resolve the parameters that the phone APP send the command,there are 3 parameters of servo debug command,the other command has just one parameter. - */ - //% weight=98 blockId=startbit_cgetArgs block="Get bluetooth command|%str|argument at %index" - //% index.min=1 index.max=3 - //% subcategory=Bluetooth - export function startbit_getArgs(str: string, index: number): number { - let cmdType = startbit_analyzeBluetoothCmd(str); - if (cmdType == startbit_CmdType.NO_COMMAND) { - return startbit_CarRunCmdType.COMMAND_ERRO; - } else { - let dataIndex = 7; - let subLegth = 2; - if (index == 2) { - dataIndex = 10; - subLegth = 2; - } else if (index == 3) { - dataIndex = 13; - subLegth = 4; - } - if (cmdType == startbit_CmdType.SERVO) { - if (str.length < 17) { - return startbit_CmdType.NO_COMMAND; - } - } - if ( - (index == 1 && str.length < 10) || - (index == 2 && str.length < 13) || - (index == 3 && str.length < 17) - ) { - return 0; - } - let strArgs = str.substr(dataIndex, subLegth); - let arg = strToNumber(strArgs); - if (arg == -1) return 0; - return arg; - } - } - - /** - * Returns the enumeration of the command type, which can be compared with this module after obtaining the bluetooth command type sent by the mobile phone APP. - */ - //% weight=97 blockId=startbit_getBluetoothCmdtype block="Bluetooth command type %type" - //% subcategory=Bluetooth - export function startbit_getBluetoothCmdtype(type: startbit_CmdType): number { - return type; - } - - /** - * The command type of the tank is stop, go ahead, back, turn left, turn right, slow down, turn left slowly, turn right slowly. - */ - //% weight=96 blockId=startbit_getRunCarType block="Car run type %type" - //% subcategory=Bluetooth - export function startbit_getRunCarType(type: startbit_CarRunCmdType): number { - return type; - } - - /** - * The distance from the ultrasonic obstacle is the standard command, which is sent to the mobile phone. The APP will indicate the distance of the ultrasonic obstacle. - */ - //% weight=95 blockId=startbit_convertUltrasonic block="Convert ultrasonic distance %data" - //% subcategory=Bluetooth - export function startbit_convertUltrasonic(data: number): string { - let cmdStr: string = "CMD|03|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * The conversion temperature value to standard command, sent to the mobile phone, and the APP displays the current temperature. - */ - //% weight=94 blockId=startbit_convertTemperature block="Convert temperature %data" - //% subcategory=Bluetooth - export function startbit_convertTemperature(data: number): string { - let cmdStr: string = "CMD|04|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Convert the light value to the standard command and send it to the mobile phone. The APP displays the current light level (0~255). - */ - //% weight=93 blockId=startbit_convertLight block="Convert light %data" - //% subcategory=Bluetooth - export function startbit_convertLight(data: number): string { - let cmdStr: string = "CMD|06|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Convert the battery value to the standard command and send it to the mobile phone. The APP displays the current voltage. - */ - //% weight=92 blockId=startbit_convertBattery blockGap=50 block="Convert battery %data" - //% subcategory=Bluetooth - export function startbit_convertBattery(data: number): string { - let cmdStr: string = "CMD|07|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Convert the hand cmd to phone app - */ - //% weight=51 blockId=startbit_convertHandCmd blockGap=50 block="Convert uHand:bit %data" - export function startbit_convertHandCmd(data: number): string { - let cmdStr: string = "CMD|15|"; - cmdStr += data.toString(); - cmdStr += "|$"; - return cmdStr; - } - - /** - * Get device mac address - */ - //% weight=100 blockId=startbit_getMacAddress block="Get device id" - //% subcategory=Bluetooth - export function startbit_getMacAddress(): string { - return macStr + "$"; - } - const ASR_I2C_ADDR = 0x79; const ASR_RESULT_ADDR = 100; @@ -1767,42 +979,12 @@ namespace Informatiktheater { return buf[0]; } + // TODO: What is this doing? //% weight=85 blockId=startbit_ASRSETMODE block="Set to |%mode mode" export function startbit_ASRSETMODE(mode: ASRMode) { WireWriteDataArray(ASR_I2C_ADDR, ASR_MODE_ADDR, mode); } - //% weight=84 blockId=startbit_ASRREAD block="Read Data" - //% subcategory=Sensor - export function startbit_ASRREAD(): number { - let val = WireReadDataArray(ASR_I2C_ADDR, ASR_RESULT_ADDR, 1); - return val; - } - - /** - * @param idNum is a number, eg: 1 - * @param words is text, eg: "ni hao" - */ - //% weight=83 blockId=startbit_ASRAddWords block="Add idNum|%idNum words|%words" - //% subcategory=Sensor - export function startbit_ASRAddWords(idNum: number, words: string) { - let buf = pins.createBuffer(words.length + 2); - buf[0] = ASR_ADD_WORDS_ADDR; - buf[1] = idNum; - for (let i = 0; i < words.length; i++) { - buf[2 + i] = words.charCodeAt(i); - } - pins.i2cWriteBuffer(ASR_I2C_ADDR, buf); - basic.pause(50); - } - - //% weight=82 blockId=startbit_ASRWORDSERASE block="Erase Data" - //% subcategory=Sensor - export function startbit_ASRWORDSERASE() { - WireWriteDataArray(ASR_I2C_ADDR, ASR_WORDS_ERASE_ADDR, null); - basic.pause(60); - } - const MP3_I2C_ADDR = 0x7b; const MP3_PLAY_NUM_ADDR = 1; const MP3_PLAY_ADDR = 5; @@ -1831,40 +1013,6 @@ namespace Informatiktheater { OFF = MP3_SINGLE_LOOP_OFF_ADDR, } - //% weight=87 blockId=startbit_MP3_BUTTON block="MP3 |%button music" - //% subcategory=Sensor - export function startbit_MP3_BUTTON(button: startbit_mp3button) { - WireWriteDataArray(MP3_I2C_ADDR, button, null); - basic.pause(20); - } - - /** - * @param value is a number, eg: 20 - */ - //% weight=88 blockId=startbit_MP3_VOL block="MP3 VOL |%value" - //% subcategory=Sensor - export function startbit_MP3_VOL(value: number) { - WireWriteDataArray(MP3_I2C_ADDR, MP3_VOL_VALUE_ADDR, value); - basic.pause(20); - } - - //% weight=85 blockId=startbit_MP3_SINGLE_LOOP blockGap=50 block="MP3 SINGLE LOOP |%state" - //% subcategory=Sensor - export function startbit_MP3_SINGLE_LOOP(state: startbit_mp3Loop) { - WireWriteDataArray(MP3_I2C_ADDR, state, null); - basic.pause(20); - } - - /** - * @param num is a number, eg: 1 - */ - //% weight=86 blockId=startbit_MP3_PLAY_NUM block="MP3 PLAY NUM|%num" - //% subcategory=Sensor - export function startbit_MP3_PLAY_NUM(num: number) { - WireWriteDataArray(MP3_I2C_ADDR, MP3_PLAY_NUM_ADDR, num); - basic.pause(20); - } - export enum startbit_LineFollowerSensors { //% block="S1" S1, @@ -1877,15 +1025,15 @@ namespace Informatiktheater { } export enum startbit_LineColor { - //% block="Black" + //% block="Schwarz" Black, - //% block="White" + //% block="Weiss" White, } const LINE_FOLLOWER_I2C_ADDR = 0x78; - //% weight=95 blockId=startbit_line_followers blockGap=50 block="Line follower %lineFollowerSensor in %LineColor ?" + //% weight=95 blockId=startbit_line_followers blockGap=50 block="Linienfolger %lineFollowerSensor in %LineColor ?" //% inlineInputMode=inline //% subcategory=Sensor export function startbit_line_followers( From f21499d4af6c0b0865c3be2f38cfdcb0c93738a6 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 16:14:41 +0100 Subject: [PATCH 004/253] Adapted pxt file --- pxt.json | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/pxt.json b/pxt.json index 4bb2989..028e75d 100644 --- a/pxt.json +++ b/pxt.json @@ -1,23 +1,21 @@ { - "name": "StartbitV2", - "version": "0.0.1", - "description": "Blocks for Hiwonder StartbitV2", - "license": "MIT", - "dependencies": { - "core": "*", - "RGBSonar": "github:Hiwonder/RGBSonar#v0.0.2" - }, - "files": [ - "README.md", - "StartbitV2.ts", - "StartbitRGBLight.ts", - "sendbuffer.asm", - "_locales/zh/StartbitV2-strings.json", - "_locales/zh/StartbitV2-jsdoc-strings.json" - ], - "testFiles": [ - "test.ts" - ], - "public": true, - "preferredEditor": "tsprj" + "name": "Informatiktheater", + "version": "0.0.1", + "description": "Blöcke fürs Informatiktheater (Hiwonder StartbitV2)", + "license": "MIT", + "dependencies": { + "core": "*", + "RGBSonar": "github:Hiwonder/RGBSonar#v0.0.2" + }, + "files": [ + "README.md", + "StartbitV2.ts", + "StartbitRGBLight.ts", + "sendbuffer.asm", + "_locales/zh/StartbitV2-strings.json", + "_locales/zh/StartbitV2-jsdoc-strings.json" + ], + "testFiles": ["test.ts"], + "public": true, + "preferredEditor": "tsprj" } From 4996ac3d98068d5b64bfe105b480ac5d74746975 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 16:23:58 +0100 Subject: [PATCH 005/253] Changed weight for init func --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index dadeaf6..f585056 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -145,7 +145,7 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=86 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" + //% weight=93 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: From 6462c19d14e7e4f73dcb943c4ea65d5e808b8f24 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 16:31:03 +0100 Subject: [PATCH 006/253] Revert change in pxt --- pxt.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pxt.json b/pxt.json index 028e75d..c9078f2 100644 --- a/pxt.json +++ b/pxt.json @@ -1,7 +1,7 @@ { - "name": "Informatiktheater", + "name": "StartbitV2", "version": "0.0.1", - "description": "Blöcke fürs Informatiktheater (Hiwonder StartbitV2)", + "description": "Blocks for Hiwonder StartbitV2", "license": "MIT", "dependencies": { "core": "*", From 6ca83c2fb6d141ae65b3f5c593bbab20fba612a2 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 31 Jan 2023 16:35:20 +0100 Subject: [PATCH 007/253] revert last change --- StartbitV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index f585056..ea6de92 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -145,7 +145,7 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=93 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" + //% weight=86 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: @@ -1025,9 +1025,9 @@ namespace Informatiktheater { } export enum startbit_LineColor { - //% block="Schwarz" + //% block="Black" Black, - //% block="Weiss" + //% block="White" White, } From 65b741f12ae09a3a5d9181d1f44d705616362425 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 10:23:42 +0100 Subject: [PATCH 008/253] small typo --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ea6de92..1d6a547 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -773,7 +773,7 @@ namespace Informatiktheater { /** * Get the condition of the line follower sensor */ - //% weight=96 blockId=startbit_readLineFollowerStatus block="Linenfolger Status|%status" + //% weight=96 blockId=startbit_readLineFollowerStatus block="Linienfolger Status|%status" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower From 1a6c03ab533b242ecade0c7400a24d4c444fb8df Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 10:54:40 +0100 Subject: [PATCH 009/253] set min/max values for brightness; translated some fields; Removed unused code --- StartbitV2.ts | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1d6a547..9935d21 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -19,20 +19,20 @@ namespace Informatiktheater { } export enum startbit_lineFollower { - //% blockId="S1_OUT_S2_OUT" block="Sensor1 and sensor2 are out black line" + //% blockId="S1_OUT_S2_OUT" block="Sensor 1 und Sensor 2 sind ausserhalb der schwarzen Linie" S1_OUT_S2_OUT = 0x00, - //% blockId="S1_OUT_S2_IN" block="Sensor2 in black line but sensor1 not" + //% blockId="S1_OUT_S2_IN" block="Sensor 2 auf schwarzer Linie aber Sensor 1 nicht" S1_OUT_S2_IN = 0x01, - //% blockId="S1_IN_S2_OUT" block="Sensor1 in black line but sensor2 not" + //% blockId="S1_IN_S2_OUT" block="Sensor 1 auf schwarzer Linie aber Sensor 2 nicht" S1_IN_S2_OUT = 0x02, - //% blockId="S1_IN_S2_IN" block="Sensor1 and sensor2 are in black line " + //% blockId="S1_IN_S2_IN" block="Sensor 1 und Sensor 2 auf schwarzer Linie" S1_IN_S2_IN = 0x03, } export enum startbit_Servos { - //% block="servo 1" + //% block="Servo 1" Servo1 = 0x01, - //% block="servo 2" + //% block="Servo 2" Servo2 = 0x02, } @@ -682,7 +682,6 @@ namespace Informatiktheater { let c = max - min; let hue = 0; let segment = 0; - let shift = 0; if (c == 0) return 0; if (r > g && r > b) { segment = (60.0 * (g - b)) / c; @@ -723,17 +722,6 @@ namespace Informatiktheater { return enable_value; } - function enableLightSensor(interrupts: boolean) { - setAmbientLightGain(DEFAULT_AGAIN); - if (interrupts) { - setAmbientLightIntEnable(1); - } else { - setAmbientLightIntEnable(0); - } - enablePower(); - setMode(AMBIENT_LIGHT, 1); - } - function setAmbientLightGain(drive: number) { let val = i2cread(APDS9960_CONTROL); /* Set bits in register to given value */ @@ -877,9 +865,10 @@ namespace Informatiktheater { * Set the brightness of the strip. This flag only applies to future operation. * @param brightness a measure of LED brightness in 0-255. eg: 255 */ - //% blockId="startbit_setBrightness" block="Setze Helligkeit %brightness" + //% blockId="startbit_setBrightness" block="Setze Helligkeit auf Wert %brightness" //% weight=100 //% subcategory=LED + //% number.min = 0 number.max=255 number.defl=255 export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); } From 2f60873cfbbca568fbef3912733987b0201094bf Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 11:01:45 +0100 Subject: [PATCH 010/253] fixed min/max error --- StartbitV2.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 9935d21..5da2bab 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -865,10 +865,11 @@ namespace Informatiktheater { * Set the brightness of the strip. This flag only applies to future operation. * @param brightness a measure of LED brightness in 0-255. eg: 255 */ - //% blockId="startbit_setBrightness" block="Setze Helligkeit auf Wert %brightness" + //% blockId="startbit_setBrightness" + //% block="Setze Helligkeit auf Wert %brightness" + //% brightness.min = 0 brightness.max=255 brightness.defl=255 //% weight=100 //% subcategory=LED - //% number.min = 0 number.max=255 number.defl=255 export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); } From 3cf69467044e7daf0e7628f905821627d70412c9 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 11:06:03 +0100 Subject: [PATCH 011/253] Remove chinese locales and vscode specific stuff --- .vscode/settings.json | 19 --- .vscode/tasks.json | 36 ---- _locales/zh/StartbitV2-jsdoc-strings.json | 83 --------- _locales/zh/StartbitV2-strings.json | 195 ---------------------- 4 files changed, 333 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 .vscode/tasks.json delete mode 100644 _locales/zh/StartbitV2-jsdoc-strings.json delete mode 100644 _locales/zh/StartbitV2-strings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e431228..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "editor.formatOnType": true, - "files.autoSave": "afterDelay", - "files.watcherExclude": { - "**/.git/objects/**": true, - "**/built/**": true, - "**/node_modules/**": true, - "**/yotta_modules/**": true, - "**/yotta_targets": true, - "**/pxt_modules/**": true - }, - "search.exclude": { - "**/built": true, - "**/node_modules": true, - "**/yotta_modules": true, - "**/yotta_targets": true, - "**/pxt_modules": true - } -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 441d7d1..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,36 +0,0 @@ - -// A task runner that calls the PXT compiler and -{ - "version": "0.1.0", - - // The command is pxt. Assumes that PXT has been installed using npm install -g pxt - "command": "pxt", - - // The command is a shell script - "isShellCommand": true, - - // Show the output window always. - "showOutput": "always", - - "tasks": [{ - "taskName": "deploy", - "isBuildCommand": true, - "problemMatcher": "$tsc", - "args": [""] - }, { - "taskName": "build", - "isTestCommand": true, - "problemMatcher": "$tsc", - "args": [""] - }, { - "taskName": "clean", - "isTestCommand": true, - "problemMatcher": "$tsc", - "args": [""] - }, { - "taskName": "serial", - "isTestCommand": true, - "problemMatcher": "$tsc", - "args": [""] - }] -} diff --git a/_locales/zh/StartbitV2-jsdoc-strings.json b/_locales/zh/StartbitV2-jsdoc-strings.json deleted file mode 100644 index dfd9687..0000000 --- a/_locales/zh/StartbitV2-jsdoc-strings.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "StartbitV2.startbit_Init":"初始化,请在开机时执行", - "StartbitV2.startbit_belt_initRGBLight":"初始化灯带,请在开机时执行", - "StartbitV2.startbit_init_colorSensor":"初始化颜色传感器,请在开机时执行", - "StartbitV2.startbit_convertHandCmd":"转换uHand指令给App", - - "StartbitV2.setServo":"设置pwm舵机的转动范围,编号指接在StartV2上的端口号,角度,时长指转到指定角度需要的时间,单位毫秒", - "StartbitV2.getServosAngle":"获取舵机角度", - "StartbitV2.startbit_setBusServo": "设置总线舵机运行,角度范围-120~120", - "StartbitV2.startbit_setMotorSpeed":"设置马达1和马达2的速度,速度范围-100到100,可控制坦克车行进和转弯", - "StartbitV2.startbit_fan_speed":"控制风扇旋转", - "StartbitV2.startbit_setFanSpeed":"设置风扇的速度", - - "StartbitV2.startbit_getSoundVolume":"获取声音传感器检测到的音量等级,范围0到255", - "StartbitV2.startbit_getBatVoltage":"获取当前供电电压,单位是mV", - "StartbitV2.startbit_ext_output":"设置扩展口输出高低电平", - "StartbitV2.startbit_ext_io_status":"检测卡扩展口的高低电平状态", - - "StartbitV2.onstartbit_custom_ir_pressed":"红外检测到指定的用户自定义的码值时触发", - "StartbitV2.onstartbit_remote_ir_pressed":"红外检测到指定的遥控器按键按下时触发", - "StartbitV2.startbit_ir_learn_mode":"进入红外学习模式,码编号范围1到10", - "StartbitV2.startbit_send_ir_data":"发送自定义红外码", - "StartbitV2.startbit_send_learn_data":"发送红外学习码,码编号范围1到10", - "StartbitV2.startbit_send_remote_data":"发送红外遥控器码", - - "StartbitV2.startbit_setBrightness":"设置光的强度,一定要在显示灯光之前设置,这样才起到效果,范围0到255", - "StartbitV2.startbit_setPixelRGB":"设置彩灯颜色,设置完成后请执行显示彩灯操作", - "StartbitV2.startbit_setPixelRGBArgs":"设置彩灯颜色,参数是颜色的索引,红色,橙色,黄色,绿色,蓝色,靛蓝色,紫罗兰色,紫色,白色对应1到9", - "StartbitV2.startbit_showLight":"显示彩灯,和设置彩灯颜色配合使用,设置完彩灯颜色后必须执行显示彩灯完成显示", - "StartbitV2.startbit_clearLight":"清除彩灯颜色,关闭彩灯", - - "StartbitV2.startbit_analyzeBluetoothCmd":"解析手机APP发送的蓝牙命令类型,一共有9种命令类型:行进命令,舵机调试命令(预留),获取超声波距离命令,获取温度命令,获取声音大小等级命令,获取光线等级命令,设置彩灯颜色命令,电池电量,鸣笛命令,固件版本信息命令", - "StartbitV2.startbit_getArgs":"解析手机App发送的命令参数,舵机调试命令有3个参数,其余都只有一个参数", - "StartbitV2.startbit_getBluetoothCmdtype":"枚举蓝牙命令类型", - "StartbitV2.startbit_getRunCarType":"获取坦克车行进命令类型,有停止、前进、后退、左转、右转、慢速前进,慢速左转,慢速右转", - - "StartbitV2.startbit_convertTemperature":"转换温度值为标准命令,发送到手机端,APP会显示当前温度", - "StartbitV2.startbit_convertLight":"转换光线值为标准命令,发送到手机端,APP会显示当前光线等级(0~255)", - "StartbitV2.startbit_convertBattery":"转换电压值,发送到手机端,APP会显示当前电压", - - "StartbitV2.startbit_checkCurrentColor":"可以获得颜色传感器检测到颜色", - "StartbitV2.startbit_avoidSensor":"获得避障传感器状态,从而知道前方有没有障碍物,返回1遇到障碍物,返回0没有遇到障碍物", - "StartbitV2.startbit_readLineFollowerStatus":"获得巡线传感器状态", - "StartbitV2.startbit_line_followers":"判断巡线传感器的状态", - "StartbitV2.startbit_touchButton":"检测触摸按键是否有按下,有按下返回1,没有按下返回0", - "StartbitV2.startbit_ultrasonic":"获得超声波模块测试到的障碍物的距离", - "StartbitV2.startbit_getKnobValue":"获取旋钮的ad值", - "StartbitV2.startbit_lineSensorValue":"获取巡线传感器的ad值", - - "StartbitV2.startbit_connectWifi":"配置Wifi模块连接到网络", - "StartbitV2.startbit_isConnectedWifi":"检测Wifi模块是否连接成功", - "StartbitV2.startbit_send_getMac":"发送配对请求", - "StartbitV2.onstartbit_getMac":"当收到设备ID时触发", - "StartbitV2.startbit_getMacAddress":"获取到设备ID字符串,与蓝牙发送结合起来使用", - "StartbitV2.startbit_readAngle":"Microbit向单片机发送查询单片机指令", - - "StartbitV2.startbit_runActionGroup":"让舵机控制板运行指定动作组指定次数", - "StartbitV2.startbit_stopActionGroup":"让舵机控制板停止当前运行的动作组", - "StartbitV2.startbit_sendAttitude":"向舵机控制板发送Microbit的姿态", - - "StartbitV2.startbit_getphotosensitiveValue":"获取光敏传感器的ad值", - "StartbitV2.startbit_photosensitiveSensor":"获得光敏传感器的状态,返回1表示检测到光亮,返回0表示没有检测到光亮", - - "StartbitV2.startbit_digitaltube":"设置数码管接口, 显示亮度以及显示位数(1-4)", - "StartbitV2.startbit_showNumber":"显示一个整数, 可以是负数", - "StartbitV2.startbit_showbit":"在指定位置显示一个数字, 数字的范围是 0-15", - "StartbitV2.startbit_showhex":"以十六进制显示数字", - "StartbitV2.startbit_showDP":"显示或隐藏小数点, 位置(0-3), true时显示, false时隐藏", - "StartbitV2.startbit_intensity":"设置显示亮度(0-8)", - "StartbitV2.startbit_off":"关闭显示功能(不会影响显示内容)", - "StartbitV2.startbit_on":"开启显示", - "StartbitV2.startbit_clear":"清除显示", - - "StartbitV2.startbit_ASRSETMODE":"设置识别模式:1循环识别模式;2口令模式;3按键模式。设置的识别模式可以掉电保存", - "StartbitV2.startbit_ASRREAD":"获取识别结果", - "StartbitV2.startbit_ASRAddWords":"添加词条,添加的词条可以掉电保存", - "StartbitV2.startbit_ASRWORDSERASE":"擦除所有设置的词条", - - "StartbitV2.startbit_MP3_BUTTON":"播放,暂停,上一首,下一首,", - "StartbitV2.startbit_MP3_VOL":"调整播放音量,需要在播放前设置,范围0-30", - "StartbitV2.startbit_MP3_SINGLE_LOOP":"开启或者关闭单曲循环,需要在播放后设置", - "StartbitV2.startbit_MP3_PLAY_NUM":"播放指定序号的歌曲,歌曲需要放在sd卡里,名称为MP3的文件夹里,并且歌曲名称以4位数字开头,如0001,0100,1000" -} diff --git a/_locales/zh/StartbitV2-strings.json b/_locales/zh/StartbitV2-strings.json deleted file mode 100644 index 73447ec..0000000 --- a/_locales/zh/StartbitV2-strings.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "StartbitV2.startbit_Init|block": "初始化StartbitV2", - "StartbitV2.ultrasonic_init|block":"初始化超声波传感器|%port", - "StartbitV2.touchSensor_init|block":"初始化触摸传感器|%port", - "StartbitV2.lineFollowSensor_init|block":"初始化巡线传感器|%port", - "StartbitV2.knobSensor_init|block":"初始化旋钮模块|%port", - "StartbitV2.photosensitiveSensor_init|block":"初始化光敏传感器|%port", - "StartbitV2.fanSensor_init|block":"初始化风扇模块|%port", - "StartbitV2.MP3_init|block":"初始化MP3模块|%port", - "StartbitV2.ASR_init|block":"初始化语音识别模块|%port", - "StartbitV2.lineFollow_iic_init|block":"初始化四路巡线传感器|%port", - "StartbitV2.avoidSensor_init|block":"初始化避障传感器|%port", - - "StartbitV2.startbit_iic.port3|block":"接口3", - "StartbitV2.startbit_iic.port4|block":"接口4", - "StartbitV2.startbit_iic.port6|block":"接口6", - - "StartbitV2.startbit_setBusServo|block": "设置总线舵机|%port|编号(数组类型) %index|角度(数组类型)(-120~120) %angle|运行时间 %duration", - "StartbitV2.startbit_setMotorSpeed|block": "设置电机1速度(-100~100)|%speed1|和电机2|速度 %speed2", - "StartbitV2.startbit_getBatVoltage|block":"电量值(mV)", - "StartbitLights.Light1|block":"彩灯1", - "StartbitLights.Light2|block":"彩灯2", - "StartbitLights.Light3|block":"彩灯3", - "StartbitLights.Light4|block":"彩灯4", - "StartbitLights.Light5|block":"彩灯5", - "StartbitLights.Light6|block":"彩灯6", - "StartbitLights.All|block":"全部", - "StartbitLightsBelt.Light1|block":"彩灯1", - "StartbitLightsBelt.Light2|block":"彩灯2", - "StartbitLightsBelt.Light3|block":"彩灯3", - "StartbitLightsBelt.Light4|block":"彩灯4", - "StartbitLightsBelt.Light5|block":"彩灯5", - "StartbitLightsBelt.Light6|block":"彩灯6", - "StartbitLightsBelt.Light7|block":"彩灯7", - "StartbitLightsBelt.Light8|block":"彩灯8", - "StartbitLightsBelt.Light9|block":"彩灯9", - "StartbitLightsBelt.Light10|block":"彩灯10", - "StartbitLightsBelt.Light11|block":"彩灯11", - "StartbitLightsBelt.Light12|block":"彩灯12", - "StartbitLightsBelt.Light13|block":"彩灯13", - "StartbitLightsBelt.Light14|block":"彩灯14", - "StartbitLightsBelt.Light15|block":"彩灯15", - "StartbitLightsBelt.All|block":"全部", - "StartbitV2.startbit_setPixelRGB|block":"设置|%lightoffset|颜色为 %rgb", - "StartbitV2.startbit_setPixelRGBArgs|block":"设置|%lightoffset|颜色为 %rgb", - "StartbitV2.startbit_showLight|block":"显示彩灯", - "StartbitV2.startbit_clearLight|block":"关闭彩灯", - "StartbitV2.startbit_setBrightness|block":"设置RGB灯亮度 %brightness", - "StartbitV2.setstartbitRun|block":"设置startbit %runType", - "StartbitV2.startbit_Colors.Red|block":"红色", - "StartbitV2.startbit_Colors.Green|block":"绿色", - "StartbitV2.startbit_Colors.Blue|block":"蓝色", - "StartbitV2.startbit_Colors.White|block":"白色", - "StartbitV2.startbit_Colors.Black|block":"黑色", - "StartbitV2.startbit_Colors.None|block":"未识别", - "StartbitV2.startbit_PinIOStatusPinIOStatus.Low|block":"高电平", - "StartbitV2.startbit_PinIOStatus.Hight|block":"低电平", - "StartbitRGBColors.Red|block":"红色", - "StartbitRGBColors.Orange|block":"橙色", - "StartbitRGBColors.Yellow|block":"黄色", - "StartbitRGBColors.Green|block":"绿色", - "StartbitRGBColors.Blue|block":"蓝色", - "StartbitRGBColors.Indigo|block":"靛蓝色", - "StartbitRGBColors.Violet|block":"紫罗兰色", - "StartbitRGBColors.Purple|block":"紫色", - "StartbitRGBColors.White|block":"白色", - "StartbitV2.ASRMode.mode1|block":"循环识别", - "StartbitV2.ASRMode.mode2|block":"口令识别", - "StartbitV2.ASRMode.mode3|block":"按键识别", - "StartbitV2.startbit_mp3button.PLAY|block":"播放", - "StartbitV2.startbit_mp3button.PAUSE|block":"暂停", - "StartbitV2.startbit_mp3button.PREV|block":"上一首", - "StartbitV2.startbit_mp3button.NEXT|block":"下一首", - "StartbitV2.startbit_mp3Loop.ON|block":"开启", - "StartbitV2.startbit_mp3Loop.OFF|block":"关闭", - "StartbitV2.startbit_analyzeBluetoothCmd|block":"获取蓝牙命令类型 %str", - "StartbitV2.startbit_getArgs|block":"获取蓝牙命令|%str|参数 %index", - "StartbitV2.startbit_getBluetoothCmdtype|block":"蓝牙命令类型 %type", - "StartbitV2.startbit_getRunCarType|block":"车辆行进命令类型 %type", - "StartbitV2.startbit_CmdType.NO_COMMAND|block":"无效的命令", - "StartbitV2.startbit_CmdType.CAR_RUN|block":"车辆行进命令", - "StartbitV2.startbit_CmdType.ROBOT_RUN|block":"机器人控制命令", - "StartbitV2.startbit_CmdType.SERVO|block":"舵机控制命令", - "StartbitV2.startbit_CmdType.ULTRASONIC|block":"超声波距离查询命令", - "StartbitV2.startbit_CmdType.TEMPERATURE|block":"温度查询命令", - "StartbitV2.startbit_CmdType.LIGHT|block":"光线查询命令", - "StartbitV2.startbit_CmdType.BATTERY|block":"电量查询命令", - "StartbitV2.startbit_CmdType.RGB_LIGHT|block":"彩灯控制命令", - "StartbitV2.startbit_CmdType.BAT|block":"电量命令", - "StartbitV2.startbit_CmdType.DIDI|block":"鸣笛命令", - "StartbitV2.startbit_CmdType.VERSION|block":"读取固件信息命令", - "StartbitV2.startbit_CmdType.READ_ANGLE|block":"回读角度", - "StartbitV2.startbit_CmdType.RGB_BELT|block":"控制灯带", - "StartbitV2.startbit_CmdType.WIFI_MODE|block":"Wifi模式", - "StartbitV2.startbit_CmdType.GET_MAC|block":"配对请求", - "StartbitV2.startbit_CmdType.GET_HAND_CMD|block":"uHand:bit命令", - "StartbitV2.startbit_CarRunCmdType.STOP|block":"停止", - "StartbitV2.startbit_CarRunCmdType.GO_AHEAD|block":"前进", - "StartbitV2.startbit_CarRunCmdType.GO_BACK|block":"后退", - "StartbitV2.startbit_CarRunCmdType.TURN_LEFT|block":"左转", - "StartbitV2.startbit_CarRunCmdType.TURN_RIGHT|block":"右转", - "StartbitV2.startbit_CarRunCmdType.GO_AHEAD_SLOW|block":"慢速前进", - "StartbitV2.startbit_CarRunCmdType.TURN_LEFT_SLOW|block":"慢速左转", - "StartbitV2.startbit_CarRunCmdType.TURN_RIGHT_SLOW|block":"慢速右转", - "StartbitV2.startbit_CarRunCmdType.COMMAND_ERRO|block":"无效的命令", - "StartbitV2.startbit_convertUltrasonic|block":"转换超声波命令 %data", - "StartbitV2.startbit_convertTemperature|block":"转换温度命令 %data", - "StartbitV2.startbit_convertLight|block":"转换光线命令 %data", - "StartbitV2.startbit_convertBattery|block":"转换电量命令 %data", - "StartbitV2.startbit_ext_output|block":"设置扩展口|管脚 %pin|%out", - "StartbitV2.startbit_ext_io_status|block":"扩展口状态 %pin", - "StartbitV2.startbit_lineFollower.S1_IN_S2_IN|block":"传感器1和传感器2在黑线内", - "StartbitV2.startbit_lineFollower.S1_IN_S2_OUT|block":"传感器1在黑线内,传感器2在黑线外", - "StartbitV2.startbit_lineFollower.S1_OUT_S2_IN|block":"传感器1在黑线外,传感器2在黑线内", - "StartbitV2.startbit_lineFollower.S1_OUT_S2_OUT|block":"传感器1和传感器2在黑线外", - "StartbitV2.startbit_colorSensorPort.port4|block":"接口4", - "StartbitV2.startbit_busServoPort.port6|block":"接口6", - "StartbitV2.AvoidSensor.Sensor_1|block":"避障传感器1", - "StartbitV2.AvoidSensor.Sensor_2|block":"避障传感器2", - "StartbitV2.startbit_ultrasonicPort.port1|block":"接口1", - "StartbitV2.startbit_ultrasonicPort.port2|block":"接口2", - "StartbitV2.startbit_init_colorSensor|block":"初始化颜色传感器 %port", - "StartbitV2.startbit_checkCurrentColor|block":"检测到颜色 %color", - "StartbitV2.startbit_avoidSensor|block":"避障传感器检测到障碍物", - "StartbitV2.startbit_fan_speed|block":"设置风扇|速度 %speed", - "StartbitV2.startbit_readLineFollowerStatus|block":"巡线传感器|%status", - "StartbitV2.startbit_ultrasonic|block":"超声波模块测试到障碍物距离(Cm)", - "StartbitV2.startbit_knobPort.port1|block":"接口1", - "StartbitV2.startbit_getKnobValue|block":"旋钮ad值(0~255)", - "StartbitV2.startbit_photosensitivePort.port1|block":"接口1", - "StartbitV2.startbit_PhotosensitiveSensor.port1|block":"接口1", - "StartbitV2.startbit_getphotosensitiveValue|block":"光敏ad值(0~255)", - "StartbitV2.startbit_photosensitiveSensor|block":"光敏传感器检测到光亮", - "StartbitV2.startbit_touchKeyPort.port1|block":"接口1", - "StartbitV2.startbit_touchKeyPort.port2|block":"接口2", - "StartbitV2.startbit_touchButton|block":"触摸按钮被按下", - "StartbitV2.startbit_lineSensorValue|block":"获取巡线传感器|%sensor|的ad值", - "StartbitV2.startbit_LineFollowerSensor.LFSensor_1|block":"循线传感器1", - "StartbitV2.startbit_LineFollowerSensor.LFSensor_2|block":"循线传感器2", - "StartbitV2.startbit_lineFollowPort.port1|block":"接口1", - "StartbitV2.startbit_connectWifi|block":"配置连接到Wifi,名称|%ssid|和密码 %passwrd", - "StartbitV2.startbit_isConnectedServer|block":"设备连接服务器是否成功?", - "StartbitV2.startbit_send_getMac|block":"发送配对请求", - "StartbitV2.onstartbit_getMac|block":"当startbit收到设备ID时执行", - "StartbitV2.startbit_getMacAddress|block":"设备ID", - "StartbitV2.startbit_belt_initRGBLight|block":"初始化灯带端口 %port", - "StartbitV2.startbit_belt_setPixelRGB|block":"设置灯带|%lightoffset|颜色 %rgb", - "StartbitV2.startbit_belt_showLight|block":"显示灯带", - "StartbitV2.startbit_belt_clearLight|block":"关闭灯带", - "StartbitV2.startbit_sendSofa|block":"发送沙发状态指令 %sofa", - "StartbitV2.SofaStatus.VACATION|block":"空闲", - "StartbitV2.SofaStatus.OCCUPIED|block":"有人", - "StartbitV2.startbit_Servos.Servo1|block":"舵机1", - "StartbitV2.startbit_Servos.Servo2|block":"舵机2", - "StartbitV2.startbit_readAngle|block":"发送读|%servo|角度命令", - "StartbitV2.getServosAngle|block":"获取|%servo|角度(-120~120)", - "StartbitV2.onStartbit_getAngle|block":"当读取到|%servo|角度时执行", - "StartbitV2.setPwmServo|block":"设置PWM舵机|转动范围 %range|编号 %index|角度 %angle|时长 %duration", - "StartbitV2.setArrayServo|block":"设置PWM舵机|转动范围 %range|编号(数组类型) %index|角度(数组类型) %angle|时长 %duration", - "StartbitV2.setBusServo|block":"设置总线舵机|ID %index|角度 %angle|时长 %duration", - "StartbitV2.startbit_runActionGroup|block":"运行动作组|编号 %index|次数 %times", - "StartbitV2.startbit_stopActionGroup|block":"停止当前动作组", - "StartbitV2.startbit_sendAttitude|block":"发送姿态 旋转|%pitch| 横滚|%roll", - "StartbitV2.startbit_actionRunover|block":"动作组运行完成", - "StartbitV2.startbit_setFanSpeed|block":"设置风扇速度(-100~100) |%speed1", - "StartbitV2.startbit_fanPort.port1|block":"接口1", - "StartbitV2.startbit_fanPort.port2|block":"接口2", - "StartbitV2.startbit_digitaltube|block":"设置数码管|%port|亮度 %intensity|显示位数 %count", - "StartbitV2.startbit_showNumber|block":"数码管显示整数| %num", - "StartbitV2.startbit_showbit|block":"数码管显示整数(0-15)| %num|位置 %bit", - "StartbitV2.startbit_showhex|block":"数码管显示十六进制数| %num", - "StartbitV2.startbit_showDP|block":"数码管在位置| %bit|显示小数点 %show", - "StartbitV2.startbit_intensity|block":"设置数码管显示亮度| %val", - "StartbitV2.startbit_off|block":"关闭数码管显示", - "StartbitV2.startbit_on|block":"开启数码管显示", - "StartbitV2.startbit_clear|block":"清除数码管显示", - "StartbitV2.startbit_digitaltubePort.port1|block":"接口1", - "StartbitV2.startbit_digitaltubePort.port2|block":"接口2", - "StartbitV2.startbit_convertHandCmd|block":"转换uHand:bit指令 %data", - "StartbitV2.startbit_ASRSETMODE|block":"语音识别模块设置为%mode模式", - "StartbitV2.startbit_ASRREAD|block":"语音识别模块获取识别词条编号", - "StartbitV2.startbit_ASRAddWords|block":"语音识别模块添加词条编号|%idnum 拼音|%words", - "StartbitV2.startbit_ASRWORDSERASE|block":"擦除全部词条", - "StartbitV2.startbit_LineColor.Black|block":"黑线", - "StartbitV2.startbit_LineColor.White|block":"白线", - "StartbitV2.startbit_LineFollowerSensors.S1|block":"传感器1", - "StartbitV2.startbit_LineFollowerSensors.S2|block":"传感器2", - "StartbitV2.startbit_LineFollowerSensors.S3|block":"传感器3", - "StartbitV2.startbit_LineFollowerSensors.S4|block":"传感器4", - "StartbitV2.startbit_line_followers|block":"四路巡线模块|%lineFollowerSensor 检测到|%LineColor ?", - "StartbitV2.startbit_MP3_BUTTON|block":"MP3模块 |%button 歌曲", - "StartbitV2.startbit_MP3_VOL|block":"MP3模块音量 |%value", - "StartbitV2.startbit_MP3_SINGLE_LOOP|block":"MP3模块单曲循环 |%state", - "StartbitV2.startbit_MP3_PLAY_NUM|block":"MP3模块播放序号|%num 歌曲" -} From 6a22ae7a502faa93b1c3a0df29dcb214901c75c5 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 11:13:32 +0100 Subject: [PATCH 012/253] Consistent casing --- StartbitV2.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 5da2bab..a914ef3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -45,7 +45,7 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="Initialisiere Ultraschall|port %port" + //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|port %port" export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -75,7 +75,7 @@ namespace Informatiktheater { let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="Initialisiere Linienfolger-Sensor|port %port" + //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|port %port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -110,7 +110,7 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="Initialisiere Dreh-Sensor|port %port" + //% weight=99 blockId=knobSensor_init block="initialisiere Dreh-Sensor|port %port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -145,7 +145,7 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=86 blockId=lineFollow_iic_init block="Initialisiere Linienfolger iic|port %port" + //% weight=86 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|port %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: @@ -167,7 +167,7 @@ namespace Informatiktheater { /** * Startbit initialization, please execute at boot time */ - //% weight=100 blockId=startbit_Init block="Initialisiere Informatiktheater" + //% weight=100 blockId=startbit_Init block="initialisiere Informatiktheater" export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -357,7 +357,7 @@ namespace Informatiktheater { /** * Set the angle of servo 1 to 8, range of 0~270 degree */ - //% weight=100 blockId=setServo block="Setze PWM Servo Distanz %range|Index %index|Winkel %angle|Dauer %duration" + //% weight=100 blockId=setServo block="setze PWM Servo Distanz %range|Index %index|Winkel %angle|Dauer %duration" //% angle.min=0 angle.max=270 //% inlineInputMode=inline //% subcategory=Servo/Motor @@ -387,7 +387,7 @@ namespace Informatiktheater { /** * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. */ - //% weight=96 blockId=startbit_setMotorSpeed block="Setze Motor1 Geschwindigkeit(-100 bis +100)|%speed1|und Motor2|Geschwindigkeit %speed2" + //% weight=96 blockId=startbit_setMotorSpeed block="setze Motor1 Geschwindigkeit(-100 bis +100)|%speed1|und Motor2|Geschwindigkeit %speed2" //% speed1.min=-100 speed1.max=100 //% speed2.min=-100 speed2.max=100 //% subcategory=Servo/Motor @@ -789,7 +789,7 @@ namespace Informatiktheater { /** * Get the line follower sensor port ad value */ - //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="Hole Linienfolger Sensor|%sensor|ad Wert" + //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="hole Linienfolger Sensor|%sensor|ad Wert" //% subcategory=Sensor export function startbit_lineSensorValue( sensor: startbit_LineFollowerSensor @@ -839,7 +839,7 @@ namespace Informatiktheater { /** * Get the ad value of the knob moudule */ - //% weight=92 blockId=startbit_getKnobValue block="Hole Dreh-Sensor|Wert (0~255)" + //% weight=92 blockId=startbit_getKnobValue block="hole Dreh-Sensor|Wert (0~255)" //% subcategory=Sensor export function startbit_getKnobValue(): number { let adValue = pins.analogReadPin(knobPin); @@ -866,7 +866,7 @@ namespace Informatiktheater { * @param brightness a measure of LED brightness in 0-255. eg: 255 */ //% blockId="startbit_setBrightness" - //% block="Setze Helligkeit auf Wert %brightness" + //% block="setze Helligkeit auf Wert %brightness" //% brightness.min = 0 brightness.max=255 brightness.defl=255 //% weight=100 //% subcategory=LED @@ -877,7 +877,7 @@ namespace Informatiktheater { /** * Set RGB Color argument */ - //% weight=99 blockId=startbit_setPixelRGBArgs block="Setze|%lightoffset|Farbe auf %rgb" + //% weight=99 blockId=startbit_setPixelRGBArgs block="setze|%lightoffset|Farbe auf %rgb" //% subcategory=LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, From 8e94c1786957863c497e4de56645222475bea583 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 11:51:34 +0100 Subject: [PATCH 013/253] renamed mapping func. --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index a914ef3..db7fd09 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -268,11 +268,11 @@ namespace Informatiktheater { } if (arg2Int > 1000) arg2Int = 1000; if (arg1Int == 1) { - servo1Angle = mapRGB(arg2Int, 0, 1000, 0, 240); + servo1Angle = mapValue(arg2Int, 0, 1000, 0, 240); servo1Angle -= 120; control.raiseEvent(MESSAGE_ANGLE, 1); } else if (arg1Int == 2) { - servo2Angle = mapRGB(arg2Int, 0, 1000, 0, 240); + servo2Angle = mapValue(arg2Int, 0, 1000, 0, 240); servo2Angle -= 120; control.raiseEvent(MESSAGE_ANGLE, 2); } @@ -367,7 +367,7 @@ namespace Informatiktheater { angle: number, duration: number = 300 ) { - let position = mapRGB(angle, 0, range, 500, 2500); + let position = mapValue(angle, 0, range, 500, 2500); let buf = pins.createBuffer(10); buf[0] = 0x55; @@ -904,7 +904,7 @@ namespace Informatiktheater { lhRGBLight.clear(); } - function mapRGB( + function mapValue( x: number, in_min: number, in_max: number, From 76ba59668103d5337a506cdf91172d39a85968f4 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 13:10:27 +0100 Subject: [PATCH 014/253] edited pxt.json --- pxt.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pxt.json b/pxt.json index c9078f2..e88e8a2 100644 --- a/pxt.json +++ b/pxt.json @@ -1,7 +1,7 @@ { - "name": "StartbitV2", - "version": "0.0.1", - "description": "Blocks for Hiwonder StartbitV2", + "name": "Informatiktheater", + "version": "0.0.2", + "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { "core": "*", From f085abdeaa1b8be00b866180407c24934855bb5c Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 13:15:57 +0100 Subject: [PATCH 015/253] removed chinese locales from pxt --- pxt.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pxt.json b/pxt.json index e88e8a2..2735725 100644 --- a/pxt.json +++ b/pxt.json @@ -11,9 +11,7 @@ "README.md", "StartbitV2.ts", "StartbitRGBLight.ts", - "sendbuffer.asm", - "_locales/zh/StartbitV2-strings.json", - "_locales/zh/StartbitV2-jsdoc-strings.json" + "sendbuffer.asm" ], "testFiles": ["test.ts"], "public": true, From 2e118efb0eb7e805ac7ccdd28d9ddf891ba502e6 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 13:33:20 +0100 Subject: [PATCH 016/253] removed rgbsonar dependency --- pxt.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pxt.json b/pxt.json index 2735725..0792598 100644 --- a/pxt.json +++ b/pxt.json @@ -4,8 +4,7 @@ "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { - "core": "*", - "RGBSonar": "github:Hiwonder/RGBSonar#v0.0.2" + "core": "*" }, "files": [ "README.md", From 152cf317e821fb4f28c74c054ee546a20d3f6abb Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 14:13:42 +0100 Subject: [PATCH 017/253] removed remaining MP3 and ASR stuff --- StartbitV2.ts | 52 +-------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index db7fd09..066dc77 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,7 +1,7 @@ /* StartbitV2 package */ -//% weight=10 icon="\uf013" color=#2896ff +//% weight=10 icon="\uf630" color=#2896ff namespace Informatiktheater { export enum startbit_Colors { //% block="Rot" @@ -914,22 +914,6 @@ namespace Informatiktheater { return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; } - const ASR_I2C_ADDR = 0x79; - - const ASR_RESULT_ADDR = 100; - const ASR_WORDS_ERASE_ADDR = 101; - const ASR_MODE_ADDR = 102; - const ASR_ADD_WORDS_ADDR = 160; - - export enum ASRMode { - //% block="1" - mode1 = 0x01, - //% block="2" - mode2 = 0x02, - //% block="3" - mode3 = 0x03, - } - function II2Cread(reg: number): Buffer { let val = pins.i2cReadBuffer(reg, 1); return val; @@ -969,40 +953,6 @@ namespace Informatiktheater { return buf[0]; } - // TODO: What is this doing? - //% weight=85 blockId=startbit_ASRSETMODE block="Set to |%mode mode" - export function startbit_ASRSETMODE(mode: ASRMode) { - WireWriteDataArray(ASR_I2C_ADDR, ASR_MODE_ADDR, mode); - } - - const MP3_I2C_ADDR = 0x7b; - const MP3_PLAY_NUM_ADDR = 1; - const MP3_PLAY_ADDR = 5; - const MP3_PAUSE_ADDR = 6; - const MP3_PREV_ADDR = 8; - const MP3_NEXT_ADDR = 9; - const MP3_VOL_VALUE_ADDR = 12; - const MP3_SINGLE_LOOP_ON_ADDR = 13; - const MP3_SINGLE_LOOP_OFF_ADDR = 14; - - export enum startbit_mp3button { - //% block="PLAY" - PLAY = MP3_PLAY_ADDR, - //% block="PAUSE" - PAUSE = MP3_PAUSE_ADDR, - //% block="PREV" - PREV = MP3_PREV_ADDR, - //% block="NEXT" - NEXT = MP3_NEXT_ADDR, - } - - export enum startbit_mp3Loop { - //% block="ON" - ON = MP3_SINGLE_LOOP_ON_ADDR, - //% block="OFF" - OFF = MP3_SINGLE_LOOP_OFF_ADDR, - } - export enum startbit_LineFollowerSensors { //% block="S1" S1, From cae7c707527f58a7320a5f23a64ff6852a214db9 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 15:39:01 +0100 Subject: [PATCH 018/253] some minor refactorings --- StartbitV2.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 066dc77..f030594 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -45,7 +45,7 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|port %port" + //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall| %port" export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -110,7 +110,7 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="initialisiere Dreh-Sensor|port %port" + //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|%port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -354,10 +354,7 @@ namespace Informatiktheater { } else return -1; } - /** - * Set the angle of servo 1 to 8, range of 0~270 degree - */ - //% weight=100 blockId=setServo block="setze PWM Servo Distanz %range|Index %index|Winkel %angle|Dauer %duration" + //% weight=100 blockId=setServo block="setze Servomotor %index| auf Winkel %angle Grad|für Dauer %duration|Bereich %range Grad" //% angle.min=0 angle.max=270 //% inlineInputMode=inline //% subcategory=Servo/Motor @@ -387,7 +384,7 @@ namespace Informatiktheater { /** * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. */ - //% weight=96 blockId=startbit_setMotorSpeed block="setze Motor1 Geschwindigkeit(-100 bis +100)|%speed1|und Motor2|Geschwindigkeit %speed2" + //% weight=96 blockId=startbit_setMotorSpeed block="setze Geschwindigkeit für |Motor 1 %speed1|und Motor 2 %speed2" //% speed1.min=-100 speed1.max=100 //% speed2.min=-100 speed2.max=100 //% subcategory=Servo/Motor @@ -813,7 +810,7 @@ namespace Informatiktheater { /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=90 blockId=startbit_ultrasonic block="Ultraschall|Distanz (cm)" + //% weight=90 blockId=startbit_ultrasonic block="hole Ultraschall|Distanz (cm)" //% subcategory=Sensor export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); @@ -839,7 +836,7 @@ namespace Informatiktheater { /** * Get the ad value of the knob moudule */ - //% weight=92 blockId=startbit_getKnobValue block="hole Dreh-Sensor|Wert (0~255)" + //% weight=92 blockId=startbit_getKnobValue block="hole Drehknopf|Wert (0~255)" //% subcategory=Sensor export function startbit_getKnobValue(): number { let adValue = pins.analogReadPin(knobPin); @@ -867,7 +864,7 @@ namespace Informatiktheater { */ //% blockId="startbit_setBrightness" //% block="setze Helligkeit auf Wert %brightness" - //% brightness.min = 0 brightness.max=255 brightness.defl=255 + //% brightness.min=0 brightness.max=255 brightness.defl=255 //% weight=100 //% subcategory=LED export function startbit_setBrightness(brightness: number): void { @@ -904,6 +901,7 @@ namespace Informatiktheater { lhRGBLight.clear(); } + // TODO: This will NOT clip values! should we add clipping ?! function mapValue( x: number, in_min: number, From 745ef05bd54919335a00971dc0dc81154e1eef96 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 15:53:31 +0100 Subject: [PATCH 019/253] reordered component and clearer descr. --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index f030594..de3ee5b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,7 +1,7 @@ /* StartbitV2 package */ -//% weight=10 icon="\uf630" color=#2896ff +//% weight=10 icon="\uf6fa" color=#2896ff namespace Informatiktheater { export enum startbit_Colors { //% block="Rot" @@ -75,7 +75,7 @@ namespace Informatiktheater { let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|port %port" + //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor| %port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -110,7 +110,7 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|%port" + //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf| %port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -145,7 +145,7 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=86 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|port %port" + //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic| %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: From 91f76c824798df0481ebd2fc2031b0f1fc2e20a7 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 16:25:11 +0100 Subject: [PATCH 020/253] more consistent initializers --- StartbitV2.ts | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index de3ee5b..afb2d87 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,7 +1,7 @@ /* StartbitV2 package */ -//% weight=10 icon="\uf6fa" color=#2896ff +//% weight=10 icon="\uf5fc" color=#2896ff namespace Informatiktheater { export enum startbit_Colors { //% block="Rot" @@ -37,15 +37,13 @@ namespace Informatiktheater { } export enum startbit_ultrasonicPort { - //% block="Port 1" port1 = 0x01, - //% block="Port 2" port2 = 0x02, } let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall| %port" + //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|Port %port" export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -69,13 +67,12 @@ namespace Informatiktheater { let touchSensorPin: DigitalPin; export enum startbit_lineFollowPort { - //% block="Port 1" port1 = 0x01, } let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor| %port" + //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|Port %port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -105,12 +102,11 @@ namespace Informatiktheater { } export enum startbit_knobPort { - //% block="Port 1" port1 = 0x01, } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf| %port" + //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|Port %port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -119,33 +115,13 @@ namespace Informatiktheater { } } - export enum startbit_photosensitivePort { - //% block="Port 1" - port1 = 0x01, - } - - export enum startbit_PhotosensitiveSensor { - //% block="Port 1" - port1 = 0x00, - } - - export enum startbit_fanPort { - //% block="Port 1" - port1, - //% block="Port 2" - port2, - } - export enum startbit_iic { - //% block="Port 3" port3 = 0x03, - //% block="Port 4" port4 = 0x04, - //% block="Port 6" port6 = 0x06, } - //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic| %port" + //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|Port %port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: From 968327cf9c648ff33fcf295e90b321d01295ebc5 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 17:07:44 +0100 Subject: [PATCH 021/253] even more consistent initializers --- StartbitV2.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index afb2d87..fa515cc 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,7 +1,7 @@ /* StartbitV2 package */ -//% weight=10 icon="\uf5fc" color=#2896ff +//% weight=10 icon="\uf013" color=#2896ff namespace Informatiktheater { export enum startbit_Colors { //% block="Rot" @@ -43,9 +43,9 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|Port %port" - export function ultrasonic_init(port: startbit_ultrasonicPort) { - switch (port) { + //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|Pin %p" + export function ultrasonic_init(p: startbit_ultrasonicPort) { + switch (p) { case startbit_ultrasonicPort.port1: echoPin = DigitalPin.P2; trigPin = DigitalPin.P1; @@ -57,13 +57,6 @@ namespace Informatiktheater { } } - export enum startbit_touchKeyPort { - //% block="Port 1" - port1 = 0x01, - //% block="Port 2" - port2 = 0x02, - } - let touchSensorPin: DigitalPin; export enum startbit_lineFollowPort { From 0c8a376110bded6385d07932df4605dd1842631d Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 17:46:44 +0100 Subject: [PATCH 022/253] removed unicode icon; removed Port string --- StartbitV2.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index fa515cc..7a4da30 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,7 +1,7 @@ /* StartbitV2 package */ -//% weight=10 icon="\uf013" color=#2896ff +//% weight=10 color=#2896ff namespace Informatiktheater { export enum startbit_Colors { //% block="Rot" @@ -30,9 +30,7 @@ namespace Informatiktheater { } export enum startbit_Servos { - //% block="Servo 1" Servo1 = 0x01, - //% block="Servo 2" Servo2 = 0x02, } @@ -43,9 +41,9 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|Pin %p" - export function ultrasonic_init(p: startbit_ultrasonicPort) { - switch (p) { + //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|%port" + export function ultrasonic_init(port: startbit_ultrasonicPort) { + switch (port) { case startbit_ultrasonicPort.port1: echoPin = DigitalPin.P2; trigPin = DigitalPin.P1; @@ -65,7 +63,7 @@ namespace Informatiktheater { let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|Port %port" + //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|%port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -99,7 +97,7 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|Port %port" + //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|%port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -114,7 +112,7 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|Port %port" + //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|%port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: @@ -323,8 +321,10 @@ namespace Informatiktheater { } else return -1; } - //% weight=100 blockId=setServo block="setze Servomotor %index| auf Winkel %angle Grad|für Dauer %duration|Bereich %range Grad" + //% weight=100 blockId=setServo + //% block="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" //% angle.min=0 angle.max=270 + //% duration.shadow=timePicker //% inlineInputMode=inline //% subcategory=Servo/Motor export function setPwmServo( From 805be395737d7e32aa57aff8b271c4682d96a2c8 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 17:50:21 +0100 Subject: [PATCH 023/253] try to correct bug in argument list --- StartbitV2.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 7a4da30..dab710e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -321,6 +321,7 @@ namespace Informatiktheater { } else return -1; } + // TODO: Why is parameter list not mapped correctly to function argument list ? //% weight=100 blockId=setServo //% block="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" //% angle.min=0 angle.max=270 @@ -328,10 +329,10 @@ namespace Informatiktheater { //% inlineInputMode=inline //% subcategory=Servo/Motor export function setPwmServo( - range: startbit_servorange, index: number = 1, angle: number, - duration: number = 300 + duration: number = 300, + range: startbit_servorange ) { let position = mapValue(angle, 0, range, 500, 2500); From 8db177f202e5e8b1fd39aea60657a1f1b0173152 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 1 Feb 2023 18:04:50 +0100 Subject: [PATCH 024/253] Added servo index --- StartbitV2.ts | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index dab710e..68e99a0 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -248,13 +248,6 @@ namespace Informatiktheater { handleCmd = ""; } - function checkADPortValue(value: number): number { - if (value == -1) return 2; - if (value <= 0x2e) return 0; - else if (value >= 0xaa) return 1; - else return 2; //未识别电平状态 - } - function findIndexof( src: string, strFind: string, @@ -321,15 +314,30 @@ namespace Informatiktheater { } else return -1; } - // TODO: Why is parameter list not mapped correctly to function argument list ? + export enum ServoIndex { + //% block="S1" + S1, + //% block="S2" + S2, + //% block="S3" + S3, + //% block="S4" + S4, + //% block="S5" + S5, + //% block="S6" + S6, + } + //% weight=100 blockId=setServo //% block="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" //% angle.min=0 angle.max=270 + //% index.defl=1 //% duration.shadow=timePicker //% inlineInputMode=inline //% subcategory=Servo/Motor export function setPwmServo( - index: number = 1, + index: ServoIndex = 1, angle: number, duration: number = 300, range: startbit_servorange @@ -933,9 +941,9 @@ namespace Informatiktheater { } export enum startbit_LineColor { - //% block="Black" + //% block="Schwarz" Black, - //% block="White" + //% block="Weiss" White, } From 124cee6d4875c716be1b06a61f6f4b6cd1b28623 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 07:49:55 +0100 Subject: [PATCH 025/253] German localisation; Removed unused vars/code --- StartbitV2.ts | 159 +++++++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 61 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 68e99a0..af9c49e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,28 +4,42 @@ //% weight=10 color=#2896ff namespace Informatiktheater { export enum startbit_Colors { - //% block="Rot" + //% block="Red" + //% block.loc.de="Rot" Red = 0x01, - //% block="Grün" + //% block="Green" + //% block.log.de="Grün" Green = 0x02, - //% block="Blau" + //% block="Blue" + //% block.loc.de="Blau" Blue = 0x03, - //% block="Schwarz" + //% block="Black" + //% block.loc.de="Schwarz" Black = 0x04, - //% block="Weiss" + //% block="White" + //% block.loc.de="Weiss" White = 0x05, - //% block="Leer" + //% block="Empty" + //% block.loc.de="Leer" None = 0x06, } export enum startbit_lineFollower { - //% blockId="S1_OUT_S2_OUT" block="Sensor 1 und Sensor 2 sind ausserhalb der schwarzen Linie" + //% blockId="S1_OUT_S2_OUT" + //% block="Sensor 1 and sensor 2 beyond black line" + //% block.loc.de="Sensor 1 und Sensor 2 sind ausserhalb der schwarzen Linie" S1_OUT_S2_OUT = 0x00, - //% blockId="S1_OUT_S2_IN" block="Sensor 2 auf schwarzer Linie aber Sensor 1 nicht" + //% blockId="S1_OUT_S2_IN + //% block="Sensor 2 on black line but not sensor 1" + //% block.loc.de="Sensor 2 auf schwarzer Linie aber Sensor 1 nicht" S1_OUT_S2_IN = 0x01, - //% blockId="S1_IN_S2_OUT" block="Sensor 1 auf schwarzer Linie aber Sensor 2 nicht" + //% blockId="S1_IN_S2_OUT" + //% block="Sensor 1 on black line but not sensor 2" + //% block.loc.de="Sensor 1 auf schwarzer Linie aber Sensor 2 nicht" S1_IN_S2_OUT = 0x02, - //% blockId="S1_IN_S2_IN" block="Sensor 1 und Sensor 2 auf schwarzer Linie" + //% blockId="S1_IN_S2_IN" + //% block="Sensor 1 and sensor 2 on black line" + //% block.loc.de="Sensor 1 und Sensor 2 auf schwarzer Linie" S1_IN_S2_IN = 0x03, } @@ -41,7 +55,10 @@ namespace Informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=91 blockId=ultrasonic_init block="initialisiere Ultraschall|%port" + //% weight=91 + //% blockId=ultrasonic_init + //% block="initialize ultrasonic |%port" + //% block.loc.de="initialisiere Ultraschall|%port" export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -55,15 +72,16 @@ namespace Informatiktheater { } } - let touchSensorPin: DigitalPin; - export enum startbit_lineFollowPort { port1 = 0x01, } let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 blockId=lineFollowSensor_init block="initialisiere Linienfolger-Sensor|%port" + //% weight=92 + //% blockId=lineFollowSensor_init + //% block="initialize line follower sensor|%port" + //% block.loc.de="initialisiere Linienfolger-Sensor|%port" export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: @@ -74,9 +92,11 @@ namespace Informatiktheater { } export enum startbit_PinIOStatus { - //% block="Aus" + //% block="Off" + //% block.loc.de="Aus" Low = 0x00, - //% block="Ein" + //% block="On" + //% block.loc.de="Ein" Hight = 0x01, } @@ -97,7 +117,10 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 blockId=knobSensor_init block="initialisiere Drehknopf|%port" + //% weight=99 + //% blockId=knobSensor_init + //% block="initialize rotating knob|%port" + //% block.loc.de="initialisiere Drehknopf|%port" export function knobSensor_init(port: startbit_knobPort) { switch (port) { case startbit_knobPort.port1: @@ -112,7 +135,10 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=93 blockId=lineFollow_iic_init block="initialisiere Linienfolger iic|%port" + //% weight=93 + //% blockId=lineFollow_iic_init + //% block="initialize line follower iic|%port" + //% block.log.de="initialisiere Linienfolger iic|%port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: @@ -132,9 +158,13 @@ namespace Informatiktheater { } /** - * Startbit initialization, please execute at boot time + * Informatiktheater initialization, please execute at boot time */ - //% weight=100 blockId=startbit_Init block="initialisiere Informatiktheater" + //% weight=100 + //% blockId=startbit_Init + //% block="initialize Informatiktheater" + //% block.loc.de="initialisiere Informatiktheater" + //% jsdoc.loc.de="Informatiktheater Initialisation, bitte beim Start ausführen." export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -158,13 +188,9 @@ namespace Informatiktheater { let MESSAGE_MAC = 0xff; let MESSAGE_ANGLE = 0x100; - let i2cPortValid: boolean = true; - let connectStatus: boolean = false; - let servo1Angle: number = 0xfff; let servo2Angle: number = 0xfff; - let macStr: string = ""; let actiongroup_finished = true; let Digitaltube: startbit_TM1640LEDs; @@ -176,9 +202,6 @@ namespace Informatiktheater { 0x39, 0x5e, 0x79, 0x71, ]; - /** - * Get the handle command. - */ function getHandleCmd() { let charStr: string = serial.readString(); handleCmd = handleCmd.concat(charStr); @@ -214,15 +237,8 @@ namespace Informatiktheater { } } if (cmd.charAt(0).compare("M") == 0 && cmd.length == 18) { - macStr = cmd.substr(1, 17); control.raiseEvent(MESSAGE_MAC, 1); } - if (cmd.compare("WIFI_S_CONNECT") == 0) { - connectStatus = true; - } - if (cmd.compare("WIFI_S_DISCONNECT") == 0) { - connectStatus = false; - } if (cmd.charAt(0).compare("S") == 0 && cmd.length == 5) { let arg1Int: number = strToNumber(cmd.substr(1, 1)); let arg2Str = cmd.substr(2, 3); @@ -329,8 +345,10 @@ namespace Informatiktheater { S6, } - //% weight=100 blockId=setServo - //% block="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" + //% weight=100 + //% blockId=setServo + //% block="set servo motor %index| angle (°) %angle| duration (ms) %duration|range (°) %range" + //% block.loc.de="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" //% angle.min=0 angle.max=270 //% index.defl=1 //% duration.shadow=timePicker @@ -359,10 +377,10 @@ namespace Informatiktheater { basic.pause(1); } - /** - * Set the speed of the number 1 motor and number 2 motor, range of -100~100, that can control the tank to go advance or turn of. - */ - //% weight=96 blockId=startbit_setMotorSpeed block="setze Geschwindigkeit für |Motor 1 %speed1|und Motor 2 %speed2" + //% weight=96 + //% blockId=startbit_setMotorSpeed + //% block="set velocity for |motor 1 %speed1|and motor 2 %speed2" + //% block.loc.de="setze Geschwindigkeit für |Motor 1 %speed1|und Motor 2 %speed2" //% speed1.min=-100 speed1.max=100 //% speed2.min=-100 speed2.max=100 //% subcategory=Servo/Motor @@ -733,10 +751,10 @@ namespace Informatiktheater { return val; } - /** - * Get the condition of the line follower sensor - */ - //% weight=96 blockId=startbit_readLineFollowerStatus block="Linienfolger Status|%status" + //% weight=96 + //% blockId=startbit_readLineFollowerStatus + //% block="Line follower status|%status" + //% block.loc.de="Linienfolger Status|%status" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower @@ -761,10 +779,10 @@ namespace Informatiktheater { } } - /** - * Get the line follower sensor port ad value - */ - //% weight=89 blockId=startbit_lineSensorValue blockGap=50 block="hole Linienfolger Sensor|%sensor|ad Wert" + //% weight=89 + //% blockId=startbit_lineSensorValue blockGap=50 + //% block="get line follower sensor|%sensor|ad value" + //% block.loc.de="hole Linienfolger Sensor|%sensor|ad Wert" //% subcategory=Sensor export function startbit_lineSensorValue( sensor: startbit_LineFollowerSensor @@ -788,7 +806,10 @@ namespace Informatiktheater { /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=90 blockId=startbit_ultrasonic block="hole Ultraschall|Distanz (cm)" + //% weight=90 + //% blockId=startbit_ultrasonic + //% block="get ultrasonic |distancse (cm)" + //% block.loc.de="hole Ultraschall|Distanz (cm)" //% subcategory=Sensor export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); @@ -814,7 +835,10 @@ namespace Informatiktheater { /** * Get the ad value of the knob moudule */ - //% weight=92 blockId=startbit_getKnobValue block="hole Drehknopf|Wert (0~255)" + //% weight=92 + //% blockId=startbit_getKnobValue + //% block="get rotating knob|value (0~255)" + //% block.loc.de="hole Drehknopf|Wert (0~255)" //% subcategory=Sensor export function startbit_getKnobValue(): number { let adValue = pins.analogReadPin(knobPin); @@ -841,18 +865,20 @@ namespace Informatiktheater { * @param brightness a measure of LED brightness in 0-255. eg: 255 */ //% blockId="startbit_setBrightness" - //% block="setze Helligkeit auf Wert %brightness" + //% block="set brightness value to %brightness" + //% block.loc.de="setze Helligkeit auf Wert %brightness" //% brightness.min=0 brightness.max=255 brightness.defl=255 + //% jsdoc.loc.de="Setze die Hellighkeit des LED Streifens. Dies gilt nur zukünftige Operationen." + //% brightness.loc.de="LED Helligkeit zwischen 0 bis 255" //% weight=100 //% subcategory=LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); } - /** - * Set RGB Color argument - */ - //% weight=99 blockId=startbit_setPixelRGBArgs block="setze|%lightoffset|Farbe auf %rgb" + //% weight=99 blockId=startbit_setPixelRGBArgs + //% block="set|%lightoffset|color to %rgb" + //% block.loc.de="setze|%lightoffset|Farbe auf %rgb" //% subcategory=LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, @@ -862,9 +888,13 @@ namespace Informatiktheater { } /** - * Display the colored lights, and set the color of the colored lights to match the use. After setting the color of the colored lights, the color of the lights must be displayed. + * Display the colored lights, and set the color of the colored lights to match the use. + * After setting the color of the colored lights, the color of the lights must be displayed. */ - //% weight=97 blockId=startbit_showLight block="Licht an" + //% weight=97 blockId=startbit_showLight + //% block="Light on" + //% block.loc.de="Licht an" + //% jsdoc.loc.de="Zeige die gefärbten Lichter" //% subcategory=LED export function startbit_showLight() { lhRGBLight.show(); @@ -873,7 +903,10 @@ namespace Informatiktheater { /** * Clear the color of the colored lights and turn off the lights. */ - //% weight=96 blockGap=50 blockId=startbit_clearLight block="Licht aus" + //% weight=96 blockGap=50 blockId=startbit_clearLight + //% block="Light off" + //% block.loc.de="Licht aus" + //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" //% subcategory=LED export function startbit_clearLight() { lhRGBLight.clear(); @@ -941,15 +974,19 @@ namespace Informatiktheater { } export enum startbit_LineColor { - //% block="Schwarz" + //% block="Black" + //% block.loc.de="Schwarz" Black, - //% block="Weiss" + //% block="White" + //% block.loc.de="Weiss" White, } const LINE_FOLLOWER_I2C_ADDR = 0x78; - //% weight=95 blockId=startbit_line_followers blockGap=50 block="Linienfolger %lineFollowerSensor in %LineColor ?" + //% weight=95 blockId=startbit_line_followers blockGap=50 + //% block="Line follower %lineFollowerSensor in %LineColor ?" + //% block.loc.de="Linienfolger %lineFollowerSensor in %LineColor ?" //% inlineInputMode=inline //% subcategory=Sensor export function startbit_line_followers( From e28f310f0bfa7fb8a241bc6f38fc1eee2b54c3c7 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 08:37:25 +0100 Subject: [PATCH 026/253] Remove verb in function description in getter functions --- StartbitV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index af9c49e..20bc577 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -782,7 +782,7 @@ namespace Informatiktheater { //% weight=89 //% blockId=startbit_lineSensorValue blockGap=50 //% block="get line follower sensor|%sensor|ad value" - //% block.loc.de="hole Linienfolger Sensor|%sensor|ad Wert" + //% block.loc.de="Linienfolger Sensor|%sensor|ad Wert" //% subcategory=Sensor export function startbit_lineSensorValue( sensor: startbit_LineFollowerSensor @@ -809,7 +809,7 @@ namespace Informatiktheater { //% weight=90 //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" - //% block.loc.de="hole Ultraschall|Distanz (cm)" + //% block.loc.de="Ultraschall|Distanz (cm)" //% subcategory=Sensor export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); @@ -838,7 +838,7 @@ namespace Informatiktheater { //% weight=92 //% blockId=startbit_getKnobValue //% block="get rotating knob|value (0~255)" - //% block.loc.de="hole Drehknopf|Wert (0~255)" + //% block.loc.de="Drehknopf|Wert (0~255)" //% subcategory=Sensor export function startbit_getKnobValue(): number { let adValue = pins.analogReadPin(knobPin); From 48df1bde3ad2f3c365821ebd3fd8c3cc89463648 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 09:57:40 +0100 Subject: [PATCH 027/253] translated blocks in startbitRGBLights --- StartbitRGBLight.ts | 203 +++++++++++++++++++------------------------- StartbitV2.ts | 2 +- 2 files changed, 90 insertions(+), 115 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index 4356ded..b19436b 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -4,75 +4,56 @@ enum StartbitRGBColors { //% block=red + //% block.loc.de=Rot Red = 1, //% block=orange + //% block.loc.de=Orange Orange = 2, //% block=yellow + //% block.loc.de=Gelb Yellow = 3, //% block=green + //% block.loc.de=Grün Green = 4, //% block=blue + //% block.loc.de=Blau Blue = 5, //% block=indigo + //% block.loc.de=Blau Indigo = 6, //% block=violet + //% block.loc.de=Violett Violet = 7, //% block=purple + //% block.loc.de=Lila Purple = 8, //% block=white - White = 9 + //% block.loc.de=Weiss + White = 9, } - enum StartbitLights { +enum StartbitLights { //% block="Light 1" + //% block.loc.de="Licht 1" Light1 = 0x00, //% block="Light 2" + //% block.loc.de="Licht 2" Light2 = 0x01, //% block="Light 3" + //% block.loc.de="Licht 3" Light3 = 0x02, //% block="Light 4" - Light4 = 0x03, + //% block.loc.de="Licht 4" + Light4 = 0x03, //% block="Light 5" - Light5 = 0x04, + //% block.loc.de="Licht 5" + Light5 = 0x04, //% block="Light 6" - Light6 = 0x05, + //% block.loc.de="Licht 6" + Light6 = 0x05, //% block="All" - All = 0x06 -} - -enum StartbitLightsBelt { - //% block="Light 1" - Light1 = 0x00, - //% block="Light 2" - Light2 = 0x01, - //% block="Light 3" - Light3 = 0x02, - //% block="Light 4" - Light4 = 0x03, - //% block="Light 5" - Light5 = 0x04, - //% block="Light 6" - Light6 = 0x05, - //% block="Light 7" - Light7 = 0x06, - //% block="Light 8" - Light8 = 0x07, - //% block="Light 9" - Light9 = 0x08, - //% block="Light 10" - Light10 = 0x09, - //% block="Light 11" - Light11 = 0x0A, - //% block="Light 12" - Light12 = 0x0B, - //% block="Light 13" - Light13 = 0x0C, - //% block="Light 14" - Light14 = 0x0D, - //% block="Light 15" - Light15 = 0x0E, - //% block="All" - All = 0x0F + //% block.loc.de="Alle" + All = 0x06, } /** @@ -84,7 +65,7 @@ enum StartbitRGBPixelMode { //% block="RGB+W" RGBW = 1, //% block="RGB (RGB format)" - RGB_RGB = 2 + RGB_RGB = 2, } /** @@ -93,13 +74,11 @@ enum StartbitRGBPixelMode { namespace StartbitRGBLight { //% shim=sendBufferAsm //% parts="QbitRGBLight" - function sendBuffer(buf: Buffer, pin: DigitalPin) { - - } + function sendBuffer(buf: Buffer, pin: DigitalPin) { } /** - * A LHQbitRGBLight class - */ + * A LHQbitRGBLight class + */ export class LHstartbitRGBLight { buf: Buffer; pin: DigitalPin; @@ -120,80 +99,67 @@ namespace StartbitRGBLight { } setBeltPixelColor(pixeloffset: number, rgb: StartbitRGBColors): void { - if (pixeloffset == 15)//全部 - { - for (let i = 0; i < this._length; i++) - { - this.setPixelRGB(i, rgb); + if (pixeloffset == 15) { + for (let i = 0; i < this._length; i++) { + this.setPixelRGB(i, rgb); } - } - else - { + } else { this.setPixelRGB(pixeloffset * 3, rgb); this.setPixelRGB(pixeloffset * 3 + 1, rgb); - this.setPixelRGB(pixeloffset*3 + 2, rgb); + this.setPixelRGB(pixeloffset * 3 + 2, rgb); } - } setPixelColor(pixeloffset: number, rgb: StartbitRGBColors): void { - if (pixeloffset == this._length)//全部 - { - for (let i = 0; i < this._length; i++) - { - this.setPixelRGB(i, rgb); + if (pixeloffset == this._length) { + for (let i = 0; i < this._length; i++) { + this.setPixelRGB(i, rgb); } - } - else - { + } else { this.setPixelRGB(pixeloffset, rgb); } - } private setPixelRGB(pixeloffset: number, rgb: StartbitRGBColors): void { - if (pixeloffset < 0 - || pixeloffset >= this._length) - return; + if (pixeloffset < 0 || pixeloffset >= this._length) return; let tureRgb = 0; - switch (rgb) - { - case StartbitRGBColors.Red: - tureRgb = 0xFF0000; - break; - - case StartbitRGBColors.Orange: - tureRgb = 0xFFA500; - break; - - case StartbitRGBColors.Yellow: - tureRgb = 0xFFFF00; - break; - - case StartbitRGBColors.Green: - tureRgb = 0x00FF00; - break; - - case StartbitRGBColors.Blue: - tureRgb = 0x0000FF; - break; - - case StartbitRGBColors.Indigo: - tureRgb = 0x4b0082; - break; - - case StartbitRGBColors.Violet: - tureRgb = 0x8a2be2; - break; - - case StartbitRGBColors.Purple: - tureRgb = 0xFF00FF; - break; - - case StartbitRGBColors.White: - tureRgb = 0xFFFFFF; - break; - } + switch (rgb) { + case StartbitRGBColors.Red: + tureRgb = 0xff0000; + break; + + case StartbitRGBColors.Orange: + tureRgb = 0xffa500; + break; + + case StartbitRGBColors.Yellow: + tureRgb = 0xffff00; + break; + + case StartbitRGBColors.Green: + tureRgb = 0x00ff00; + break; + + case StartbitRGBColors.Blue: + tureRgb = 0x0000ff; + break; + + case StartbitRGBColors.Indigo: + tureRgb = 0x4b0082; + break; + + case StartbitRGBColors.Violet: + tureRgb = 0x8a2be2; + break; + + case StartbitRGBColors.Purple: + tureRgb = 0xff00ff; + break; + + case StartbitRGBColors.White: + tureRgb = 0xffffff; + break; + } let stride = this._mode === StartbitRGBPixelMode.RGBW ? 4 : 3; pixeloffset = (pixeloffset + this.start) * stride; @@ -208,10 +174,15 @@ namespace StartbitRGBLight { green = (green * br) >> 8; blue = (blue * br) >> 8; } - this.setBufferRGB(pixeloffset, red, green, blue) + this.setBufferRGB(pixeloffset, red, green, blue); } - private setBufferRGB(offset: number, red: number, green: number, blue: number): void { + private setBufferRGB( + offset: number, + red: number, + green: number, + blue: number + ): void { if (this._mode === StartbitRGBPixelMode.RGB_RGB) { this.buf[offset + 0] = red; this.buf[offset + 1] = green; @@ -232,7 +203,11 @@ namespace StartbitRGBLight { this.show(); } } - export function create(pin: DigitalPin, numleds: number, mode: StartbitRGBPixelMode): LHstartbitRGBLight { + export function create( + pin: DigitalPin, + numleds: number, + mode: StartbitRGBPixelMode + ): LHstartbitRGBLight { let light = new LHstartbitRGBLight(); let stride = mode === StartbitRGBPixelMode.RGBW ? 4 : 3; light.buf = pins.createBuffer(numleds * stride); @@ -245,18 +220,18 @@ namespace StartbitRGBLight { } function packRGB(a: number, b: number, c: number): number { - return ((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF); + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); } function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xFF; + let r = (rgb >> 16) & 0xff; return r; } function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xFF; + let g = (rgb >> 8) & 0xff; return g; } function unpackB(rgb: number): number { - let b = (rgb) & 0xFF; + let b = rgb & 0xff; return b; } } diff --git a/StartbitV2.ts b/StartbitV2.ts index 20bc577..42c1e2c 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,5 +1,5 @@ /* - StartbitV2 package + Informatiktheater package */ //% weight=10 color=#2896ff namespace Informatiktheater { From a6d09186a7e95e78402f1d0f7ca91f3146933eee Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 11:17:49 +0100 Subject: [PATCH 028/253] use LED RGB from enum --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 42c1e2c..b1acaa3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -782,7 +782,7 @@ namespace Informatiktheater { //% weight=89 //% blockId=startbit_lineSensorValue blockGap=50 //% block="get line follower sensor|%sensor|ad value" - //% block.loc.de="Linienfolger Sensor|%sensor|ad Wert" + //% block.loc.de="Linienfolger |%sensor|ad Wert" //% subcategory=Sensor export function startbit_lineSensorValue( sensor: startbit_LineFollowerSensor @@ -882,7 +882,7 @@ namespace Informatiktheater { //% subcategory=LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, - rgb: number + rgb: StartbitRGBColors ) { lhRGBLight.setPixelColor(lightoffset, rgb); } From 63e13bdf7324fa6707ccae8adc012fb4301d1404 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 12:56:31 +0100 Subject: [PATCH 029/253] Edited comments for RGB blocks --- StartbitRGBLight.ts | 2 +- StartbitV2.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index b19436b..1965784 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -19,7 +19,7 @@ enum StartbitRGBColors { //% block.loc.de=Blau Blue = 5, //% block=indigo - //% block.loc.de=Blau + //% block.loc.de=Indigo Indigo = 6, //% block=violet //% block.loc.de=Violett diff --git a/StartbitV2.ts b/StartbitV2.ts index b1acaa3..bffce14 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -754,7 +754,7 @@ namespace Informatiktheater { //% weight=96 //% blockId=startbit_readLineFollowerStatus //% block="Line follower status|%status" - //% block.loc.de="Linienfolger Status|%status" + //% block.loc.de="Linienfolger |%status ?" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower @@ -878,7 +878,7 @@ namespace Informatiktheater { //% weight=99 blockId=startbit_setPixelRGBArgs //% block="set|%lightoffset|color to %rgb" - //% block.loc.de="setze|%lightoffset|Farbe auf %rgb" + //% block.loc.de="setze Farbe von|%lightoffset|auf %rgb" //% subcategory=LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, @@ -894,7 +894,7 @@ namespace Informatiktheater { //% weight=97 blockId=startbit_showLight //% block="Light on" //% block.loc.de="Licht an" - //% jsdoc.loc.de="Zeige die gefärbten Lichter" + //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" //% subcategory=LED export function startbit_showLight() { lhRGBLight.show(); @@ -986,7 +986,7 @@ namespace Informatiktheater { //% weight=95 blockId=startbit_line_followers blockGap=50 //% block="Line follower %lineFollowerSensor in %LineColor ?" - //% block.loc.de="Linienfolger %lineFollowerSensor in %LineColor ?" + //% block.loc.de="Linienfolger %lineFollowerSensor auf %LineColor ?" //% inlineInputMode=inline //% subcategory=Sensor export function startbit_line_followers( From 38aa59095f1b41c7d23c74dd53abced8710ea53f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 13:07:26 +0100 Subject: [PATCH 030/253] line follower without new line --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bffce14..909bf97 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -753,8 +753,8 @@ namespace Informatiktheater { //% weight=96 //% blockId=startbit_readLineFollowerStatus - //% block="Line follower status|%status" - //% block.loc.de="Linienfolger |%status ?" + //% block="Line follower status %status" + //% block.loc.de="Linienfolger %status ?" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower From 01c313d8c99aba665125f2ffeb0d20af647cfc6d Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 13:17:14 +0100 Subject: [PATCH 031/253] replacde % with $ in blocks --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 909bf97..4882036 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -753,8 +753,8 @@ namespace Informatiktheater { //% weight=96 //% blockId=startbit_readLineFollowerStatus - //% block="Line follower status %status" - //% block.loc.de="Linienfolger %status ?" + //% block="Line follower status $status" + //% block.loc.de="Linienfolger $status ?" //% subcategory=Sensor export function startbit_readLineFollowerStatus( status: startbit_lineFollower From e6b9994bed1f230014c7d7a6e4db0aeb77907d1f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 13:28:50 +0100 Subject: [PATCH 032/253] another try... --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 4882036..6e6b965 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -27,7 +27,7 @@ namespace Informatiktheater { export enum startbit_lineFollower { //% blockId="S1_OUT_S2_OUT" //% block="Sensor 1 and sensor 2 beyond black line" - //% block.loc.de="Sensor 1 und Sensor 2 sind ausserhalb der schwarzen Linie" + //% block.loc.de="Sensor1 und Sensor2 sind ausserhalb der schwarzen Linie" S1_OUT_S2_OUT = 0x00, //% blockId="S1_OUT_S2_IN //% block="Sensor 2 on black line but not sensor 1" From b4e16b9f42bfbe928779ef262a60d9d15aeafedb Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 13:40:02 +0100 Subject: [PATCH 033/253] sensor 1 -> sensor1 --- StartbitV2.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 6e6b965..b42f316 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -26,20 +26,20 @@ namespace Informatiktheater { export enum startbit_lineFollower { //% blockId="S1_OUT_S2_OUT" - //% block="Sensor 1 and sensor 2 beyond black line" + //% block="Sensor1 and sensor2 beyond black line" //% block.loc.de="Sensor1 und Sensor2 sind ausserhalb der schwarzen Linie" S1_OUT_S2_OUT = 0x00, //% blockId="S1_OUT_S2_IN - //% block="Sensor 2 on black line but not sensor 1" - //% block.loc.de="Sensor 2 auf schwarzer Linie aber Sensor 1 nicht" + //% block="Sensor2 on black line but not sensor1" + //% block.loc.de="Sensor2 auf schwarzer Linie aber Sensor1 nicht" S1_OUT_S2_IN = 0x01, //% blockId="S1_IN_S2_OUT" - //% block="Sensor 1 on black line but not sensor 2" - //% block.loc.de="Sensor 1 auf schwarzer Linie aber Sensor 2 nicht" + //% block="Sensor1 on black line but not sensor2" + //% block.loc.de="Sensor1 auf schwarzer Linie aber Sensor2 nicht" S1_IN_S2_OUT = 0x02, //% blockId="S1_IN_S2_IN" - //% block="Sensor 1 and sensor 2 on black line" - //% block.loc.de="Sensor 1 und Sensor 2 auf schwarzer Linie" + //% block="Sensor1 and sensor2 on black line" + //% block.loc.de="Sensor1 und Sensor2 auf schwarzer Linie" S1_IN_S2_IN = 0x03, } From 842606707c698fd35b8c1c792d543e3e08476309 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 15:52:27 +0100 Subject: [PATCH 034/253] Test for mp3 lists --- StartbitV2.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index b42f316..3863354 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1047,4 +1047,39 @@ namespace Informatiktheater { } return status; } + + // //% block="Trittmatte gedrückt" + // // + // export function trittmattePressed(handler: () => void) { + // handler(); + // } + + // MP3 Player stuff + + export class SongList { + TrackIndex: number = 0; + list: Array; + + //% block="setze $this auf $list " + //% x.defl=Songliste + //% x.shadow=variables_get + public createSongListArray(list: number[]) { + this.list = list; + } + + //% block="Play next track in list $this" + //% block.loc.de="nächste Songnummer in Liste $this" + public playNextTrack() { + if (this.TrackIndex < this.list.length) { + this.TrackIndex += 1; + } else { + this.TrackIndex = 0; + } + } + } + // //% block="setze $songlist auf $list " + // //% x.defl=Songliste + // //% x.shadow=variables_get + // export function createSongListArray(songlist: Array, list: number[]) { + // } } From 1da7d1102b59bb9ef6f0ae0fb2cbecfc18dbb5fd Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 16:06:32 +0100 Subject: [PATCH 035/253] more mp3 functions --- StartbitV2.ts | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 3863354..d478726 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1061,25 +1061,44 @@ namespace Informatiktheater { list: Array; //% block="setze $this auf $list " - //% x.defl=Songliste - //% x.shadow=variables_get + //% this.defl=Songliste public createSongListArray(list: number[]) { this.list = list; } //% block="Play next track in list $this" //% block.loc.de="nächste Songnummer in Liste $this" - public playNextTrack() { + public playNextTrack(): number { if (this.TrackIndex < this.list.length) { this.TrackIndex += 1; } else { this.TrackIndex = 0; } + return this.TrackIndex; + } + // + //% block="Play previous track in list $this" + //% block.loc.de="vorherige Songnummer in Liste $this" + public playPreviousTrack(): number { + if (this.TrackIndex <= 0) { + this.TrackIndex == 0; + } else { + this.TrackIndex--; + } + return this.TrackIndex; + } + + //% block="current song number in list %this" + //% block.loc.de="Aktuelle Songnummer in liste %this" + public currentTrack(): number { + return this.TrackIndex; + } + + //% block="Back to first song in list %this" + //% block.loc.de="Zurück zur ersten Songnummer in Liste %this" + public gotoFirstTrack(): number { + this.TrackIndex = 0; + return this.currentTrack(); } } - // //% block="setze $songlist auf $list " - // //% x.defl=Songliste - // //% x.shadow=variables_get - // export function createSongListArray(songlist: Array, list: number[]) { - // } } From dd309223c7b5d08da08604f70a2a50f98ba563c6 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 16:09:02 +0100 Subject: [PATCH 036/253] explicit constructor --- StartbitV2.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d478726..80f2510 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1057,9 +1057,13 @@ namespace Informatiktheater { // MP3 Player stuff export class SongList { - TrackIndex: number = 0; + TrackIndex: number; list: Array; + init(): void { + this.TrackIndex = 0; + } + //% block="setze $this auf $list " //% this.defl=Songliste public createSongListArray(list: number[]) { From cecf7663522bff6707c1f41d4c179af7a00537b0 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 16:21:05 +0100 Subject: [PATCH 037/253] default for songliste and subcategory mp3 box --- StartbitV2.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index 80f2510..c10e420 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1066,12 +1066,15 @@ namespace Informatiktheater { //% block="setze $this auf $list " //% this.defl=Songliste + //% subcategory=MP3 Box public createSongListArray(list: number[]) { this.list = list; } //% block="Play next track in list $this" //% block.loc.de="nächste Songnummer in Liste $this" + //% this.defl=Songliste + //% subcategory=MP3 Box public playNextTrack(): number { if (this.TrackIndex < this.list.length) { this.TrackIndex += 1; @@ -1083,6 +1086,8 @@ namespace Informatiktheater { // //% block="Play previous track in list $this" //% block.loc.de="vorherige Songnummer in Liste $this" + //% this.defl=Songliste + //% subcategory=MP3 Box public playPreviousTrack(): number { if (this.TrackIndex <= 0) { this.TrackIndex == 0; @@ -1094,12 +1099,16 @@ namespace Informatiktheater { //% block="current song number in list %this" //% block.loc.de="Aktuelle Songnummer in liste %this" + //% this.defl=Songliste + //% subcategory=MP3 Box public currentTrack(): number { return this.TrackIndex; } //% block="Back to first song in list %this" //% block.loc.de="Zurück zur ersten Songnummer in Liste %this" + //% this.defl=Songliste + //% subcategory=MP3 Box public gotoFirstTrack(): number { this.TrackIndex = 0; return this.currentTrack(); From 0943860b2f6f543e73535e7fc8cb5fc27c99d81b Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 16:45:32 +0100 Subject: [PATCH 038/253] without constructor --- StartbitV2.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c10e420..871b483 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1060,15 +1060,17 @@ namespace Informatiktheater { TrackIndex: number; list: Array; - init(): void { - this.TrackIndex = 0; - } + // init(): void { + // this.TrackIndex = 0; + // } //% block="setze $this auf $list " //% this.defl=Songliste + //% this.shadow=variables_get //% subcategory=MP3 Box public createSongListArray(list: number[]) { this.list = list; + this.TrackIndex = 0; } //% block="Play next track in list $this" @@ -1108,7 +1110,7 @@ namespace Informatiktheater { //% block="Back to first song in list %this" //% block.loc.de="Zurück zur ersten Songnummer in Liste %this" //% this.defl=Songliste - //% subcategory=MP3 Box + //% subcategory=MP3-Box public gotoFirstTrack(): number { this.TrackIndex = 0; return this.currentTrack(); From 8d2ffeb7e0d5c69d9af2a0b57fb1774ca243253f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 6 Feb 2023 17:12:22 +0100 Subject: [PATCH 039/253] decalare songliste --- StartbitV2.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 871b483..81493a2 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1055,6 +1055,7 @@ namespace Informatiktheater { // } // MP3 Player stuff + // export class SongList { TrackIndex: number; @@ -1067,7 +1068,7 @@ namespace Informatiktheater { //% block="setze $this auf $list " //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3 Box + //% subcategory=MP3-Box public createSongListArray(list: number[]) { this.list = list; this.TrackIndex = 0; @@ -1076,7 +1077,8 @@ namespace Informatiktheater { //% block="Play next track in list $this" //% block.loc.de="nächste Songnummer in Liste $this" //% this.defl=Songliste - //% subcategory=MP3 Box + //% this.shadow=variables_get + //% subcategory=MP3-Box public playNextTrack(): number { if (this.TrackIndex < this.list.length) { this.TrackIndex += 1; @@ -1089,7 +1091,8 @@ namespace Informatiktheater { //% block="Play previous track in list $this" //% block.loc.de="vorherige Songnummer in Liste $this" //% this.defl=Songliste - //% subcategory=MP3 Box + //% this.shadow=variables_get + //% subcategory=MP3-Box public playPreviousTrack(): number { if (this.TrackIndex <= 0) { this.TrackIndex == 0; @@ -1102,7 +1105,8 @@ namespace Informatiktheater { //% block="current song number in list %this" //% block.loc.de="Aktuelle Songnummer in liste %this" //% this.defl=Songliste - //% subcategory=MP3 Box + //% this.shadow=variables_get + //% subcategory=MP3-Box public currentTrack(): number { return this.TrackIndex; } @@ -1110,10 +1114,13 @@ namespace Informatiktheater { //% block="Back to first song in list %this" //% block.loc.de="Zurück zur ersten Songnummer in Liste %this" //% this.defl=Songliste + //% this.shadow=variables_get //% subcategory=MP3-Box public gotoFirstTrack(): number { this.TrackIndex = 0; return this.currentTrack(); } } + + let Songliste: Informatiktheater.SongList = new Informatiktheater.SongList(); } From 63284ac667bdb10ab9965f4a1073ca0bbd088b4f Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 7 Feb 2023 07:25:38 +0100 Subject: [PATCH 040/253] default factory for mp3 box --- StartbitV2.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 81493a2..444b006 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1055,15 +1055,15 @@ namespace Informatiktheater { // } // MP3 Player stuff - // export class SongList { TrackIndex: number; list: Array; - // init(): void { - // this.TrackIndex = 0; - // } + constructor() { + this.TrackIndex = 0; + this.list = [0]; + } //% block="setze $this auf $list " //% this.defl=Songliste @@ -1122,5 +1122,14 @@ namespace Informatiktheater { } } - let Songliste: Informatiktheater.SongList = new Informatiktheater.SongList(); + /** + * Creates a song list and automtically set it to a variable + */ + //% block="create song list" + //% block.loc.de="erstelle Songliste" + //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." + //% blockSetVariable=Songliste + export function createSongList(): SongList { + return undefined; + } } From 77e267774abf93dfd480cdd2a8b6a84fc95f17ab Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 7 Feb 2023 08:26:01 +0100 Subject: [PATCH 041/253] return object --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 444b006..7a92081 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1130,6 +1130,6 @@ namespace Informatiktheater { //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." //% blockSetVariable=Songliste export function createSongList(): SongList { - return undefined; + return new SongList(); } } From 1fc963a3e26ea30a747e8330dbd7cf09ff136f4f Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 7 Feb 2023 08:32:35 +0100 Subject: [PATCH 042/253] mp3 box functions without return types for stacking blocks --- StartbitV2.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 7a92081..237f43e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1079,13 +1079,12 @@ namespace Informatiktheater { //% this.defl=Songliste //% this.shadow=variables_get //% subcategory=MP3-Box - public playNextTrack(): number { + public playNextTrack() { if (this.TrackIndex < this.list.length) { this.TrackIndex += 1; } else { this.TrackIndex = 0; } - return this.TrackIndex; } // //% block="Play previous track in list $this" @@ -1093,13 +1092,12 @@ namespace Informatiktheater { //% this.defl=Songliste //% this.shadow=variables_get //% subcategory=MP3-Box - public playPreviousTrack(): number { + public playPreviousTrack() { if (this.TrackIndex <= 0) { this.TrackIndex == 0; } else { this.TrackIndex--; } - return this.TrackIndex; } //% block="current song number in list %this" @@ -1112,13 +1110,12 @@ namespace Informatiktheater { } //% block="Back to first song in list %this" - //% block.loc.de="Zurück zur ersten Songnummer in Liste %this" + //% block.loc.de="zurück zur ersten Songnummer in Liste %this" //% this.defl=Songliste //% this.shadow=variables_get //% subcategory=MP3-Box - public gotoFirstTrack(): number { + public gotoFirstTrack() { this.TrackIndex = 0; - return this.currentTrack(); } } From edd3b02faaacf1fd80c7d917b6cef73f03e73223 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 7 Feb 2023 09:03:41 +0100 Subject: [PATCH 043/253] mp3 init() in subcategory; Return list entry instead of index --- StartbitV2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 237f43e..bb58182 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1106,7 +1106,7 @@ namespace Informatiktheater { //% this.shadow=variables_get //% subcategory=MP3-Box public currentTrack(): number { - return this.TrackIndex; + return this.list[this.TrackIndex]; } //% block="Back to first song in list %this" @@ -1126,6 +1126,7 @@ namespace Informatiktheater { //% block.loc.de="erstelle Songliste" //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." //% blockSetVariable=Songliste + //% subcategory=MP3-Box export function createSongList(): SongList { return new SongList(); } From f479e2f6b56fb706f14af8bbd1f355229db75443 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 7 Feb 2023 10:07:11 +0100 Subject: [PATCH 044/253] Weights for mp3 --- StartbitV2.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index bb58182..7267dc4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1065,6 +1065,7 @@ namespace Informatiktheater { this.list = [0]; } + //% weight=99 //% block="setze $this auf $list " //% this.defl=Songliste //% this.shadow=variables_get @@ -1074,6 +1075,7 @@ namespace Informatiktheater { this.TrackIndex = 0; } + //% weight=98 //% block="Play next track in list $this" //% block.loc.de="nächste Songnummer in Liste $this" //% this.defl=Songliste @@ -1087,6 +1089,7 @@ namespace Informatiktheater { } } // + //% weight=97 //% block="Play previous track in list $this" //% block.loc.de="vorherige Songnummer in Liste $this" //% this.defl=Songliste @@ -1100,6 +1103,7 @@ namespace Informatiktheater { } } + //% weight=95 //% block="current song number in list %this" //% block.loc.de="Aktuelle Songnummer in liste %this" //% this.defl=Songliste @@ -1109,6 +1113,7 @@ namespace Informatiktheater { return this.list[this.TrackIndex]; } + //% weight=96 //% block="Back to first song in list %this" //% block.loc.de="zurück zur ersten Songnummer in Liste %this" //% this.defl=Songliste @@ -1122,6 +1127,7 @@ namespace Informatiktheater { /** * Creates a song list and automtically set it to a variable */ + //% weight=100 //% block="create song list" //% block.loc.de="erstelle Songliste" //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." From 3ff37105475c0237d4f6de4eab3570fcd7e05952 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 10:17:32 +0100 Subject: [PATCH 045/253] log -> loc typo --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 7267dc4..d45cb8d 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -138,7 +138,7 @@ namespace Informatiktheater { //% weight=93 //% blockId=lineFollow_iic_init //% block="initialize line follower iic|%port" - //% block.log.de="initialisiere Linienfolger iic|%port" + //% block.loc.de="initialisiere Linienfolger iic|%port" export function lineFollow_iic_init(port: startbit_iic) { switch (port) { case startbit_iic.port3: From 8b7228b427ac9c625f00648a5cf05a1f5ee696f5 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 11:20:58 +0100 Subject: [PATCH 046/253] servo range fix to 180degree --- StartbitV2.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d45cb8d..d6567ee 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -150,13 +150,6 @@ namespace Informatiktheater { } } - export enum startbit_servorange { - //% block="180" - range1 = 180, - //% block="270" - range2 = 270, - } - /** * Informatiktheater initialization, please execute at boot time */ @@ -347,9 +340,9 @@ namespace Informatiktheater { //% weight=100 //% blockId=setServo - //% block="set servo motor %index| angle (°) %angle| duration (ms) %duration|range (°) %range" - //% block.loc.de="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration|Bereich (°) %range" - //% angle.min=0 angle.max=270 + //% block="set servo motor %index| angle (°) %angle| duration (ms) %duration" + //% block.loc.de="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration" + //% angle.min=0 angle.max=180 //% index.defl=1 //% duration.shadow=timePicker //% inlineInputMode=inline @@ -357,10 +350,9 @@ namespace Informatiktheater { export function setPwmServo( index: ServoIndex = 1, angle: number, - duration: number = 300, - range: startbit_servorange + duration: number = 300 ) { - let position = mapValue(angle, 0, range, 500, 2500); + let position = mapValue(angle, 0, 180, 500, 2500); let buf = pins.createBuffer(10); buf[0] = 0x55; From ed526ae766185b923ea5a549aab2a175d7b6e833 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 11:38:37 +0100 Subject: [PATCH 047/253] remove led tm1640 support; renamed Licht 1 to LED 1 --- StartbitRGBLight.ts | 12 ++-- StartbitV2.ts | 164 -------------------------------------------- 2 files changed, 6 insertions(+), 170 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index 1965784..1f67976 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -34,22 +34,22 @@ enum StartbitRGBColors { enum StartbitLights { //% block="Light 1" - //% block.loc.de="Licht 1" + //% block.loc.de="LED 1" Light1 = 0x00, //% block="Light 2" - //% block.loc.de="Licht 2" + //% block.loc.de="LED 2" Light2 = 0x01, //% block="Light 3" - //% block.loc.de="Licht 3" + //% block.loc.de="LED 3" Light3 = 0x02, //% block="Light 4" - //% block.loc.de="Licht 4" + //% block.loc.de="LED 4" Light4 = 0x03, //% block="Light 5" - //% block.loc.de="Licht 5" + //% block.loc.de="LED 5" Light5 = 0x04, //% block="Light 6" - //% block.loc.de="Licht 6" + //% block.loc.de="LED 6" Light6 = 0x05, //% block="All" //% block.loc.de="Alle" diff --git a/StartbitV2.ts b/StartbitV2.ts index d6567ee..4098627 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -176,17 +176,12 @@ namespace Informatiktheater { let lhRGBLight: StartbitRGBLight.LHstartbitRGBLight; let lhRGBLightBelt: StartbitRGBLight.LHstartbitRGBLight; - let P14_ad = 0; - let MESSAGE_MAC = 0xff; let MESSAGE_ANGLE = 0x100; let servo1Angle: number = 0xfff; let servo2Angle: number = 0xfff; - let actiongroup_finished = true; - - let Digitaltube: startbit_TM1640LEDs; let TM1640_CMD1 = 0x40; let TM1640_CMD2 = 0xc0; let TM1640_CMD3 = 0x80; @@ -209,14 +204,11 @@ namespace Informatiktheater { let arg2Int: number = strToNumber(cmd.substr(3, 2)); let arg3Int: number = strToNumber(cmd.substr(5, 2)); - P14_ad = arg1Int; - if (arg3Int != -1) { currentVoltage = arg3Int * 78.63; currentVoltage = Math.round(currentVoltage); } } else if (cmd.length == 5) { - actiongroup_finished = true; } else { } } @@ -291,17 +283,6 @@ namespace Informatiktheater { return num; } - function decStrToNumber(str: string): number { - let num: number = 0; - for (let i = 0; i < str.length; i++) { - let tmp: number = converOneChar(str.charAt(i)); - if (tmp == -1) return -1; - if (i > 0) num *= 10; - num += tmp; - } - return num; - } - function converOneChar(str: string): number { if (str.compare("0") >= 0 && str.compare("9") <= 0) { return parseInt(str); @@ -392,151 +373,6 @@ namespace Informatiktheater { serial.writeBuffer(buf); } - /** - * TM1640 LED display - */ - export class startbit_TM1640LEDs { - buf: Buffer; - clk: DigitalPin; - dio: DigitalPin; - _ON: number; - brightness: number; - count: number; // number of LEDs - - /** - * initial TM1640 - */ - init(): void { - pins.digitalWritePin(this.clk, 0); - pins.digitalWritePin(this.dio, 0); - this._ON = 8; - this.buf = pins.createBuffer(this.count); - this.clear(); - } - - /** - * Start - */ - _start() { - pins.digitalWritePin(this.dio, 0); - pins.digitalWritePin(this.clk, 0); - } - - /** - * Stop - */ - _stop() { - pins.digitalWritePin(this.dio, 0); - pins.digitalWritePin(this.clk, 1); - pins.digitalWritePin(this.dio, 1); - } - - /** - * send command1 - */ - _write_data_cmd() { - this._start(); - this._write_byte(TM1640_CMD1); - this._stop(); - } - - /** - * send command3 - */ - _write_dsp_ctrl() { - this._start(); - this._write_byte(TM1640_CMD3 | this._ON | this.brightness); - this._stop(); - } - - /** - * send a byte to 2-wire interface - */ - _write_byte(b: number) { - for (let i = 0; i < 8; i++) { - pins.digitalWritePin(this.clk, 0); - pins.digitalWritePin(this.dio, (b >> i) & 1); - pins.digitalWritePin(this.clk, 1); - } - pins.digitalWritePin(this.clk, 1); - pins.digitalWritePin(this.clk, 0); - } - - intensity(val: number = 7) { - if (val < 1) { - this.off(); - return; - } - if (val > 8) val = 8; - this._ON = 8; - this.brightness = val - 1; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } - - /** - * set data to TM1640, with given bit - */ - _dat(bit: number, dat: number) { - this._write_data_cmd(); - this._start(); - this._write_byte(TM1640_CMD2 | bit % this.count); - this._write_byte(dat); - this._stop(); - this._write_dsp_ctrl(); - } - - showbit(num: number = 5, bit: number = 0) { - this.buf[bit % this.count] = _SEGMENTS[num % 16]; - this._dat(bit, _SEGMENTS[num % 16]); - } - - showNumber(num: number) { - if (num < 0) { - this._dat(0, 0x40); // '-' - num = -num; - } else this.showbit(Math.idiv(num, 1000) % 10); - this.showbit(num % 10, 3); - this.showbit(Math.idiv(num, 10) % 10, 2); - this.showbit(Math.idiv(num, 100) % 10, 1); - } - - showHex(num: number) { - if (num < 0) { - this._dat(0, 0x40); // '-' - num = -num; - } else this.showbit((num >> 12) % 16); - this.showbit(num % 16, 3); - this.showbit((num >> 4) % 16, 2); - this.showbit((num >> 8) % 16, 1); - } - - showDP(bit: number = 1, show: boolean = true) { - bit = bit % this.count; - if (show) this._dat(bit, this.buf[bit] | 0x80); - else this._dat(bit, this.buf[bit] & 0x7f); - } - - clear() { - for (let i = 0; i < this.count; i++) { - this._dat(i, 0); - this.buf[i] = 0; - } - } - - on() { - this._ON = 8; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } - - off() { - this._ON = 0; - this._write_data_cmd(); - this._write_dsp_ctrl(); - } - } - const APDS9960_I2C_ADDR = 0x39; const APDS9960_ID_1 = 0xa8; const APDS9960_ID_2 = 0x9c; From ac431e585d6a99258816161d6aa0a13b671a0bbd Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 11:53:35 +0100 Subject: [PATCH 048/253] remove leds 3 to 5 --- StartbitRGBLight.ts | 12 ------------ StartbitV2.ts | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index 1f67976..d9a21fb 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -39,18 +39,6 @@ enum StartbitLights { //% block="Light 2" //% block.loc.de="LED 2" Light2 = 0x01, - //% block="Light 3" - //% block.loc.de="LED 3" - Light3 = 0x02, - //% block="Light 4" - //% block.loc.de="LED 4" - Light4 = 0x03, - //% block="Light 5" - //% block.loc.de="LED 5" - Light5 = 0x04, - //% block="Light 6" - //% block.loc.de="LED 6" - Light6 = 0x05, //% block="All" //% block.loc.de="Alle" All = 0x06, diff --git a/StartbitV2.ts b/StartbitV2.ts index 4098627..09ac88b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -681,7 +681,7 @@ namespace Informatiktheater { if (!lhRGBLight) { lhRGBLight = StartbitRGBLight.create( DigitalPin.P15, - 6, + 6, // Silvan: Why 6 LEDS?! StartbitRGBPixelMode.RGB ); } From a0dfa71a73ed6b11cf7c5da78123dbe6097ea9e5 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 15:00:32 +0100 Subject: [PATCH 049/253] trittmatte test --- StartbitV2.ts | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 09ac88b..1518de8 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -876,11 +876,42 @@ namespace Informatiktheater { return status; } - // //% block="Trittmatte gedrückt" - // // - // export function trittmattePressed(handler: () => void) { - // handler(); - // } + // Trittmatte + + export enum startbit_trittmattePort { + port1 = 0x01, + port2 = 0x02, + port3 = 0x03, + } + //% weight=100 + //% blockId=trittmatte_init + //% block="initialize trittmatte |%port" + //% block.loc.de="initialisiere Trittmatte|%port" + //% subcategory=Trittmatte + export function trittmatte_init(port: startbit_trittmattePort) { + let pin: MicrobitPin; + switch (port) { + case startbit_trittmattePort.port1: + pin.id = 2; + break; + case startbit_trittmattePort.port2: + pin.id = 14; + break; + case startbit_trittmattePort.port3: + pin.id = 16; + break; + } + pin.setPull(inPullMode.PullUp); + pins.setEvents(pin.id, PinEventType.Touch); + } + + //% weight=1 + //% block="Trittmatte pressed" + //% block.loc.de="Trittmatte P2 gedrückt" + //% subcategory=Trittmatte + export function control.onEvent(EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, function() { + + }) // MP3 Player stuff From ea83d3862b77c5514f1392944f71e805a1dcc08b Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 15:15:01 +0100 Subject: [PATCH 050/253] missing empty event handler --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1518de8..edfcc34 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -909,9 +909,9 @@ namespace Informatiktheater { //% block="Trittmatte pressed" //% block.loc.de="Trittmatte P2 gedrückt" //% subcategory=Trittmatte - export function control.onEvent(EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, function() { + export function control.onEvent(EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, handler: () => void ){ - }) + } // MP3 Player stuff From a223fff274184db7f1623ea67d31ea4146d9a706 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 15:30:39 +0100 Subject: [PATCH 051/253] event with callback --- StartbitV2.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index edfcc34..aec6775 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -893,6 +893,11 @@ namespace Informatiktheater { switch (port) { case startbit_trittmattePort.port1: pin.id = 2; + control.onEvent( + EventBusSource.MICROBIT_ID_IO_P2, + EventBusValue.MICROBIT_PIN_EVT_RISE, + trittmatte_pressed((fromPin = pin.id)) + ); break; case startbit_trittmattePort.port2: pin.id = 14; @@ -907,10 +912,16 @@ namespace Informatiktheater { //% weight=1 //% block="Trittmatte pressed" - //% block.loc.de="Trittmatte P2 gedrückt" + //% block.loc.de="Trittmatte |%port gedrückt" //% subcategory=Trittmatte - export function control.onEvent(EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, handler: () => void ){ - + export function trittmatte_pressed( + fromPin: number, + port: startbit_trittmattePort + ) { + if (port != fromPin) { + console.log("Received event from another port"); + return; + } } // MP3 Player stuff From 4cd1afda2f3162bd4e6e2657faa409fd9df993a0 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 17:00:07 +0100 Subject: [PATCH 052/253] another try.. --- StartbitV2.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index aec6775..c917ea9 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -883,6 +883,8 @@ namespace Informatiktheater { port2 = 0x02, port3 = 0x03, } + + let trittmatte_pin: number; //% weight=100 //% blockId=trittmatte_init //% block="initialize trittmatte |%port" @@ -896,7 +898,7 @@ namespace Informatiktheater { control.onEvent( EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, - trittmatte_pressed((fromPin = pin.id)) + trittmatte_pressed() ); break; case startbit_trittmattePort.port2: @@ -912,16 +914,11 @@ namespace Informatiktheater { //% weight=1 //% block="Trittmatte pressed" - //% block.loc.de="Trittmatte |%port gedrückt" + //% block.loc.de="Trittmatte gedrückt" //% subcategory=Trittmatte - export function trittmatte_pressed( - fromPin: number, - port: startbit_trittmattePort - ) { - if (port != fromPin) { - console.log("Received event from another port"); - return; - } + export function trittmatte_pressed(handler: () => void) { + console.log("trittmatte gedrückt"); + handler(); } // MP3 Player stuff From dcabe18ec724a7fffaf9006c60c667000577837a Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 17:24:25 +0100 Subject: [PATCH 053/253] pulsed event --- StartbitV2.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c917ea9..0218ef4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -898,7 +898,9 @@ namespace Informatiktheater { control.onEvent( EventBusSource.MICROBIT_ID_IO_P2, EventBusValue.MICROBIT_PIN_EVT_RISE, - trittmatte_pressed() + () => { + console.log("pin event triggered from P2"); + } ); break; case startbit_trittmattePort.port2: @@ -908,8 +910,8 @@ namespace Informatiktheater { pin.id = 16; break; } - pin.setPull(inPullMode.PullUp); - pins.setEvents(pin.id, PinEventType.Touch); + pin.setPull(PinPullMode.PullUp); + pins.setEvents(pin.id, PinEventType.Edge); } //% weight=1 From fdd5c2e6a3b05d713939ef4209f98bae74ff90f6 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 8 Feb 2023 18:42:36 +0100 Subject: [PATCH 054/253] added pxtcore; trying to create event handler using dal --- StartbitV2.ts | 29 ++++++++++++++++++++++------- pxt.json | 3 ++- pxtcore.h | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 pxtcore.h diff --git a/StartbitV2.ts b/StartbitV2.ts index 0218ef4..4533d0b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -895,13 +895,13 @@ namespace Informatiktheater { switch (port) { case startbit_trittmattePort.port1: pin.id = 2; - control.onEvent( - EventBusSource.MICROBIT_ID_IO_P2, - EventBusValue.MICROBIT_PIN_EVT_RISE, - () => { - console.log("pin event triggered from P2"); - } - ); + // control.onEvent( + // EventBusSource.MICROBIT_ID_IO_P2, + // EventBusValue.MICROBIT_PIN_EVT_RISE, + // () => { + // console.log("pin event triggered from P2"); + // } + // ); break; case startbit_trittmattePort.port2: pin.id = 14; @@ -922,6 +922,21 @@ namespace Informatiktheater { console.log("trittmatte gedrückt"); handler(); } + /** + * Registers Trittmatte event handler. + */ + //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" + //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" + //% blockExternalInputs=1 + export function onEventTrittmatte( + src: number, + value: number, + handler: () => void, + flags: number = 0 + ) { + if (!flags) flags = EventFlags.QueueIfBusy; + pxtcore.registerWithDal(src, value, handler, flags); + } // MP3 Player stuff diff --git a/pxt.json b/pxt.json index 0792598..9fa8c57 100644 --- a/pxt.json +++ b/pxt.json @@ -10,7 +10,8 @@ "README.md", "StartbitV2.ts", "StartbitRGBLight.ts", - "sendbuffer.asm" + "sendbuffer.asm", + "pxtcore.h" ], "testFiles": ["test.ts"], "public": true, diff --git a/pxtcore.h b/pxtcore.h new file mode 100644 index 0000000..14af863 --- /dev/null +++ b/pxtcore.h @@ -0,0 +1,35 @@ +#ifndef __PXTCORE_H +#define __PXTCORE_H + +#include "MicroBit.h" +#include "MicroBitImage.h" +#include "ManagedString.h" +#include "ManagedType.h" + +namespace pxt { +void debuglog(const char *format, ...); +} + +// #define GC_GET_HEAP_SIZE() device_heap_size(0) +#define xmalloc malloc +#define xfree free + +#define GC_MAX_ALLOC_SIZE 9000 + +#define NON_GC_HEAP_RESERVATION 1024 + +#ifdef CODAL_CONFIG_H +#define MICROBIT_CODAL 1 +#else +#define MICROBIT_CODAL 0 +#define GC_BLOCK_SIZE 256 +#endif + +#if !MICROBIT_CODAL +#undef DMESG +#define DMESG NOLOG +#endif + +#undef BYTES_TO_WORDS + +#endif From 88389f2b2fabacc228cec64f31495801be80da9f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 08:01:52 +0100 Subject: [PATCH 055/253] temp. remove trittmatte --- StartbitV2.ts | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 4533d0b..9c605ec 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -922,21 +922,22 @@ namespace Informatiktheater { console.log("trittmatte gedrückt"); handler(); } - /** - * Registers Trittmatte event handler. - */ - //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" - //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" - //% blockExternalInputs=1 - export function onEventTrittmatte( - src: number, - value: number, - handler: () => void, - flags: number = 0 - ) { - if (!flags) flags = EventFlags.QueueIfBusy; - pxtcore.registerWithDal(src, value, handler, flags); - } + + // /** + // * Registers Trittmatte event handler. + // */ + // //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" + // //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" + // //% blockExternalInputs=1 + // export function onEventTrittmatte( + // src: number, + // value: number, + // handler: () => void, + // flags: number = 0 + // ) { + // if (!flags) flags = EventFlags.QueueIfBusy; + // pxtcore.registerWithDal(src, value, handler, flags); + // } // MP3 Player stuff From e7a64b8c82c54a30b0363b19021fd042aee8a324 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 09:30:15 +0100 Subject: [PATCH 056/253] trittmatte pin definition fix --- StartbitV2.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 9c605ec..c8c48f4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -884,7 +884,6 @@ namespace Informatiktheater { port3 = 0x03, } - let trittmatte_pin: number; //% weight=100 //% blockId=trittmatte_init //% block="initialize trittmatte |%port" @@ -894,23 +893,16 @@ namespace Informatiktheater { let pin: MicrobitPin; switch (port) { case startbit_trittmattePort.port1: - pin.id = 2; - // control.onEvent( - // EventBusSource.MICROBIT_ID_IO_P2, - // EventBusValue.MICROBIT_PIN_EVT_RISE, - // () => { - // console.log("pin event triggered from P2"); - // } - // ); + pin = new MicrobitPin(2); break; case startbit_trittmattePort.port2: - pin.id = 14; + pin = new MicrobitPin(14); break; case startbit_trittmattePort.port3: - pin.id = 16; + pin = new MicrobitPin(16); break; } - pin.setPull(PinPullMode.PullUp); + pin.setPull(PinPullMode.PullDown); pins.setEvents(pin.id, PinEventType.Edge); } From 6b0cee5934f7467a71ffe2f25ab69b72c2c4338e Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 14:08:55 +0100 Subject: [PATCH 057/253] Pullup for trittmatte --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c8c48f4..17eab18 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -902,8 +902,8 @@ namespace Informatiktheater { pin = new MicrobitPin(16); break; } - pin.setPull(PinPullMode.PullDown); - pins.setEvents(pin.id, PinEventType.Edge); + pin.setPull(PinPullMode.PullUp); + pins.setEvents(pin.id, PinEventType.Pulse); } //% weight=1 From 4bf3aae5e56f2d7bf657c59cb03c04c75cb5788e Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 14:28:01 +0100 Subject: [PATCH 058/253] proper types for pin setEvents() and setPull() --- StartbitV2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 17eab18..8537a5b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -890,20 +890,20 @@ namespace Informatiktheater { //% block.loc.de="initialisiere Trittmatte|%port" //% subcategory=Trittmatte export function trittmatte_init(port: startbit_trittmattePort) { - let pin: MicrobitPin; + let pin: DigitalPin; switch (port) { case startbit_trittmattePort.port1: - pin = new MicrobitPin(2); + pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: - pin = new MicrobitPin(14); + pin = DigitalPin.P14; break; case startbit_trittmattePort.port3: - pin = new MicrobitPin(16); + pin = DigitalPin.P16; break; } - pin.setPull(PinPullMode.PullUp); - pins.setEvents(pin.id, PinEventType.Pulse); + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); } //% weight=1 From c42df24ce15c53e928e1c91f675e8302c432df62 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 15:10:30 +0100 Subject: [PATCH 059/253] tried again with registerWithDal dep --- StartbitV2.ts | 31 ++++++++++++++++--------------- pxt.json | 6 +++--- pxtcore.h | 35 ----------------------------------- 3 files changed, 19 insertions(+), 53 deletions(-) delete mode 100644 pxtcore.h diff --git a/StartbitV2.ts b/StartbitV2.ts index 8537a5b..eaf332e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -915,21 +915,22 @@ namespace Informatiktheater { handler(); } - // /** - // * Registers Trittmatte event handler. - // */ - // //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" - // //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" - // //% blockExternalInputs=1 - // export function onEventTrittmatte( - // src: number, - // value: number, - // handler: () => void, - // flags: number = 0 - // ) { - // if (!flags) flags = EventFlags.QueueIfBusy; - // pxtcore.registerWithDal(src, value, handler, flags); - // } + /** + * Registers Trittmatte event handler. + */ + //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" + //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" + //% blockExternalInputs=1 + //% subcategory=Trittmatte + export function onEventTrittmatte( + src: number, + value: number, + handler: () => void, + flags: number = 0 + ) { + if (!flags) flags = EventFlags.QueueIfBusy; + pxtcore.registerWithDal(src, value, handler, flags); + } // MP3 Player stuff diff --git a/pxt.json b/pxt.json index 9fa8c57..30711db 100644 --- a/pxt.json +++ b/pxt.json @@ -4,14 +4,14 @@ "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { - "core": "*" + "core": "file:../core", + "pulse": "file:../pulse" }, "files": [ "README.md", "StartbitV2.ts", "StartbitRGBLight.ts", - "sendbuffer.asm", - "pxtcore.h" + "sendbuffer.asm" ], "testFiles": ["test.ts"], "public": true, diff --git a/pxtcore.h b/pxtcore.h deleted file mode 100644 index 14af863..0000000 --- a/pxtcore.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __PXTCORE_H -#define __PXTCORE_H - -#include "MicroBit.h" -#include "MicroBitImage.h" -#include "ManagedString.h" -#include "ManagedType.h" - -namespace pxt { -void debuglog(const char *format, ...); -} - -// #define GC_GET_HEAP_SIZE() device_heap_size(0) -#define xmalloc malloc -#define xfree free - -#define GC_MAX_ALLOC_SIZE 9000 - -#define NON_GC_HEAP_RESERVATION 1024 - -#ifdef CODAL_CONFIG_H -#define MICROBIT_CODAL 1 -#else -#define MICROBIT_CODAL 0 -#define GC_BLOCK_SIZE 256 -#endif - -#if !MICROBIT_CODAL -#undef DMESG -#define DMESG NOLOG -#endif - -#undef BYTES_TO_WORDS - -#endif From 2ec1da4ca7be0a9aea85d1f0b8a987ac2ec68ccf Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Feb 2023 16:13:02 +0100 Subject: [PATCH 060/253] removed callback functions --- StartbitV2.ts | 52 +++++++++++++++++++++++++-------------------------- pxt.json | 3 +-- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index eaf332e..5fa72a3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -906,32 +906,32 @@ namespace Informatiktheater { pins.setPull(pin, PinPullMode.PullUp); } - //% weight=1 - //% block="Trittmatte pressed" - //% block.loc.de="Trittmatte gedrückt" - //% subcategory=Trittmatte - export function trittmatte_pressed(handler: () => void) { - console.log("trittmatte gedrückt"); - handler(); - } - - /** - * Registers Trittmatte event handler. - */ - //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" - //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" - //% blockExternalInputs=1 - //% subcategory=Trittmatte - export function onEventTrittmatte( - src: number, - value: number, - handler: () => void, - flags: number = 0 - ) { - if (!flags) flags = EventFlags.QueueIfBusy; - pxtcore.registerWithDal(src, value, handler, flags); - } - + // //% weight=1 + // //% block="Trittmatte pressed" + // //% block.loc.de="Trittmatte gedrückt" + // //% subcategory=Trittmatte + // export function trittmatte_pressed(handler: () => void) { + // console.log("trittmatte gedrückt"); + // handler(); + // } + // + // /** + // * Registers Trittmatte event handler. + // */ + // //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" + // //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" + // //% blockExternalInputs=1 + // //% subcategory=Trittmatte + // export function onEventTrittmatte( + // src: number, + // value: number, + // handler: () => void, + // flags: number = 0 + // ) { + // if (!flags) flags = EventFlags.QueueIfBusy; + // pxtcore.registerWithDal(src, value, handler, flags); + // } + // // MP3 Player stuff export class SongList { diff --git a/pxt.json b/pxt.json index 30711db..7c11b2d 100644 --- a/pxt.json +++ b/pxt.json @@ -4,8 +4,7 @@ "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { - "core": "file:../core", - "pulse": "file:../pulse" + "core": "file:../core" }, "files": [ "README.md", From aa9a6f7746babed577a838ba7675dd64c953049c Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 10:14:34 +0100 Subject: [PATCH 061/253] onPulse event handler inside init --- StartbitV2.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index 5fa72a3..59d827b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -904,6 +904,28 @@ namespace Informatiktheater { } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); + + pins.onPulsed(pin, PulseValue.High, function() { + if (pins.pulseDuration() > 150000) { + Informatiktheater.startbit_setPixelRGBArgs( + StartbitLights.Light2, + StartbitRGBColors.Orange + ); + Informatiktheater.startbit_showLight(); + music.playTone(165, music.beat(BeatFraction.Quarter)); + } + }); + + pins.onPulsed(pin, PulseValue.Low, function() { + if (pins.pulseDuration() > 150000) { + Informatiktheater.startbit_setPixelRGBArgs( + StartbitLights.Light2, + StartbitRGBColors.White + ); + Informatiktheater.startbit_showLight(); + music.playTone(440, music.beat(BeatFraction.Quarter)); + } + }); } // //% weight=1 From 58f88f1c59599268f8249167882b127800a74907 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 10:24:48 +0100 Subject: [PATCH 062/253] added custom callback --- StartbitV2.ts | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 59d827b..e2a616d 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -913,6 +913,7 @@ namespace Informatiktheater { ); Informatiktheater.startbit_showLight(); music.playTone(165, music.beat(BeatFraction.Quarter)); + trittmatte_pressed(() => { }); } }); @@ -928,32 +929,14 @@ namespace Informatiktheater { }); } - // //% weight=1 - // //% block="Trittmatte pressed" - // //% block.loc.de="Trittmatte gedrückt" - // //% subcategory=Trittmatte - // export function trittmatte_pressed(handler: () => void) { - // console.log("trittmatte gedrückt"); - // handler(); - // } - // - // /** - // * Registers Trittmatte event handler. - // */ - // //% weight=20 blockGap=8 blockId="control_on_event_trittmatte" - // //%block="on event|from %src=control_event_source_id|with value %value=control_event_value_id" - // //% blockExternalInputs=1 - // //% subcategory=Trittmatte - // export function onEventTrittmatte( - // src: number, - // value: number, - // handler: () => void, - // flags: number = 0 - // ) { - // if (!flags) flags = EventFlags.QueueIfBusy; - // pxtcore.registerWithDal(src, value, handler, flags); - // } - // + //% weight=1 + //% block="Trittmatte pressed" + //% block.loc.de="Trittmatte gedrückt" + //% subcategory=Trittmatte + export function trittmatte_pressed(handler: () => void) { + handler(); + } + // MP3 Player stuff export class SongList { From 99b6b1fb31c5f1b7018013d2c328c2f32f19e9bd Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 10:51:23 +0100 Subject: [PATCH 063/253] commented out handler call --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e2a616d..b2b56b1 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -934,7 +934,7 @@ namespace Informatiktheater { //% block.loc.de="Trittmatte gedrückt" //% subcategory=Trittmatte export function trittmatte_pressed(handler: () => void) { - handler(); + // handler(); } // MP3 Player stuff From d3276245ae8e799c595f20a1ac5d1006ccfb1fa9 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 13:23:06 +0100 Subject: [PATCH 064/253] bind onPulsed on custom event block --- StartbitV2.ts | 76 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b2b56b1..e26aa90 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -904,37 +904,63 @@ namespace Informatiktheater { } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); - - pins.onPulsed(pin, PulseValue.High, function() { - if (pins.pulseDuration() > 150000) { - Informatiktheater.startbit_setPixelRGBArgs( - StartbitLights.Light2, - StartbitRGBColors.Orange - ); - Informatiktheater.startbit_showLight(); - music.playTone(165, music.beat(BeatFraction.Quarter)); - trittmatte_pressed(() => { }); - } - }); - - pins.onPulsed(pin, PulseValue.Low, function() { - if (pins.pulseDuration() > 150000) { - Informatiktheater.startbit_setPixelRGBArgs( - StartbitLights.Light2, - StartbitRGBColors.White - ); - Informatiktheater.startbit_showLight(); - music.playTone(440, music.beat(BeatFraction.Quarter)); - } - }); + // + // pins.onPulsed(pin, PulseValue.High, function() { + // if (pins.pulseDuration() > 150000) { + // Informatiktheater.startbit_setPixelRGBArgs( + // StartbitLights.Light2, + // StartbitRGBColors.Orange + // ); + // Informatiktheater.startbit_showLight(); + // music.playTone(165, music.beat(BeatFraction.Quarter)); + // trittmatte_pressed(() => { }); + // } + // }); + // + // pins.onPulsed(pin, PulseValue.Low, function() { + // if (pins.pulseDuration() > 150000) { + // Informatiktheater.startbit_setPixelRGBArgs( + // StartbitLights.Light2, + // StartbitRGBColors.White + // ); + // Informatiktheater.startbit_showLight(); + // music.playTone(440, music.beat(BeatFraction.Quarter)); + // } + // }); } + /** + * Binds code to be executed to onPulsed event + */ //% weight=1 //% block="Trittmatte pressed" - //% block.loc.de="Trittmatte gedrückt" + //% block.loc.de="Trittmatte gedrückt auf|%port" //% subcategory=Trittmatte - export function trittmatte_pressed(handler: () => void) { + export function trittmatte_pressed( + port: startbit_trittmattePort, + handler: () => void + ): void { // handler(); + let pin: DigitalPin; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + break; + } + Informatiktheater.startbit_setPixelRGBArgs( + StartbitLights.Light2, + StartbitRGBColors.White + ); + Informatiktheater.startbit_showLight(); + music.playTone(440, music.beat(BeatFraction.Quarter)); + const p = pins.pinByCfg(pin); + if (p) p.onPulsed(pulse, handler); } // MP3 Player stuff From 73075afb074c92eb860f6c8d06eb4ed7cac6d235 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 13:29:03 +0100 Subject: [PATCH 065/253] another try --- StartbitV2.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e26aa90..f01f0a3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -959,8 +959,7 @@ namespace Informatiktheater { ); Informatiktheater.startbit_showLight(); music.playTone(440, music.beat(BeatFraction.Quarter)); - const p = pins.pinByCfg(pin); - if (p) p.onPulsed(pulse, handler); + pins.onPulsed(pin, PulseValue.High, handler); } // MP3 Player stuff From 0fc6b0e285fd962a99e3818461478a5fb4c8362f Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 13:35:24 +0100 Subject: [PATCH 066/253] added missing port --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index f01f0a3..2e5d6ad 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -933,8 +933,8 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event */ //% weight=1 - //% block="Trittmatte pressed" - //% block.loc.de="Trittmatte gedrückt auf|%port" + //% block="Trittmatte pressed|on %port" + //% block.loc.de="Trittmatte gedrückt|auf|%port" //% subcategory=Trittmatte export function trittmatte_pressed( port: startbit_trittmattePort, From 112f16aaac05a7a10fe0c9713e5100e1fb4b48b3 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:00:27 +0100 Subject: [PATCH 067/253] defl port --- StartbitV2.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index 2e5d6ad..6e69244 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -934,6 +934,7 @@ namespace Informatiktheater { */ //% weight=1 //% block="Trittmatte pressed|on %port" + // port.defl=1 //% block.loc.de="Trittmatte gedrückt|auf|%port" //% subcategory=Trittmatte export function trittmatte_pressed( From 31c0929f72c5e908f9ba6a1278970fc3225e39e3 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:00:45 +0100 Subject: [PATCH 068/253] missing % --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 6e69244..d6f546f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -934,7 +934,7 @@ namespace Informatiktheater { */ //% weight=1 //% block="Trittmatte pressed|on %port" - // port.defl=1 + //% port.defl=1 //% block.loc.de="Trittmatte gedrückt|auf|%port" //% subcategory=Trittmatte export function trittmatte_pressed( From c11c084948e19ec874790f80e3970c75c3db9ed5 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:04:53 +0100 Subject: [PATCH 069/253] without possible uninitialized code --- StartbitV2.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d6f546f..fab60d9 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -954,12 +954,6 @@ namespace Informatiktheater { pin = DigitalPin.P16; break; } - Informatiktheater.startbit_setPixelRGBArgs( - StartbitLights.Light2, - StartbitRGBColors.White - ); - Informatiktheater.startbit_showLight(); - music.playTone(440, music.beat(BeatFraction.Quarter)); pins.onPulsed(pin, PulseValue.High, handler); } From 113fa54a74d77cf14ef830553ec0e804508c9194 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:22:57 +0100 Subject: [PATCH 070/253] without defl --- StartbitV2.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index fab60d9..b56d75c 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -934,7 +934,6 @@ namespace Informatiktheater { */ //% weight=1 //% block="Trittmatte pressed|on %port" - //% port.defl=1 //% block.loc.de="Trittmatte gedrückt|auf|%port" //% subcategory=Trittmatte export function trittmatte_pressed( From d3b3b0b4d4aa4e984332f952084862cf1f55a7dd Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:42:26 +0100 Subject: [PATCH 071/253] remove trittmatte initializer --- StartbitV2.ts | 282 +++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 139 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b56d75c..ee2b115 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -884,158 +884,162 @@ namespace Informatiktheater { port3 = 0x03, } - //% weight=100 - //% blockId=trittmatte_init - //% block="initialize trittmatte |%port" - //% block.loc.de="initialisiere Trittmatte|%port" - //% subcategory=Trittmatte - export function trittmatte_init(port: startbit_trittmattePort) { - let pin: DigitalPin; - switch (port) { - case startbit_trittmattePort.port1: - pin = DigitalPin.P2; - break; - case startbit_trittmattePort.port2: - pin = DigitalPin.P14; - break; - case startbit_trittmattePort.port3: - pin = DigitalPin.P16; - break; - } - pins.setEvents(pin, PinEventType.Pulse); - pins.setPull(pin, PinPullMode.PullUp); - // - // pins.onPulsed(pin, PulseValue.High, function() { - // if (pins.pulseDuration() > 150000) { - // Informatiktheater.startbit_setPixelRGBArgs( - // StartbitLights.Light2, - // StartbitRGBColors.Orange - // ); - // Informatiktheater.startbit_showLight(); - // music.playTone(165, music.beat(BeatFraction.Quarter)); - // trittmatte_pressed(() => { }); - // } - // }); - // - // pins.onPulsed(pin, PulseValue.Low, function() { - // if (pins.pulseDuration() > 150000) { - // Informatiktheater.startbit_setPixelRGBArgs( - // StartbitLights.Light2, - // StartbitRGBColors.White - // ); - // Informatiktheater.startbit_showLight(); - // music.playTone(440, music.beat(BeatFraction.Quarter)); - // } - // }); - } + // //% weight=100 + // //% blockId=trittmatte_init + // //% block="initialize trittmatte |%port" + // //% block.loc.de="initialisiere Trittmatte|%port" + // //% subcategory=Trittmatte + // export function trittmatte_init(port: startbit_trittmattePort) { + // let pin: DigitalPin; + // switch (port) { + // case startbit_trittmattePort.port1: + // pin = DigitalPin.P2; + // break; + // case startbit_trittmattePort.port2: + // pin = DigitalPin.P14; + // break; + // case startbit_trittmattePort.port3: + // pin = DigitalPin.P16; + // break; + // } + // pins.setEvents(pin, PinEventType.Pulse); + // pins.setPull(pin, PinPullMode.PullUp); + // + // pins.onPulsed(pin, PulseValue.High, function() { + // if (pins.pulseDuration() > 150000) { + // Informatiktheater.startbit_setPixelRGBArgs( + // StartbitLights.Light2, + // StartbitRGBColors.Orange + // ); + // Informatiktheater.startbit_showLight(); + // music.playTone(165, music.beat(BeatFraction.Quarter)); + // trittmatte_pressed(() => { }); + // } + // }); + // + // pins.onPulsed(pin, PulseValue.Low, function() { + // if (pins.pulseDuration() > 150000) { + // Informatiktheater.startbit_setPixelRGBArgs( + // StartbitLights.Light2, + // StartbitRGBColors.White + // ); + // Informatiktheater.startbit_showLight(); + // music.playTone(440, music.beat(BeatFraction.Quarter)); + // } + // }); +} - /** - * Binds code to be executed to onPulsed event - */ - //% weight=1 - //% block="Trittmatte pressed|on %port" - //% block.loc.de="Trittmatte gedrückt|auf|%port" - //% subcategory=Trittmatte - export function trittmatte_pressed( - port: startbit_trittmattePort, - handler: () => void - ): void { - // handler(); - let pin: DigitalPin; - switch (port) { - case startbit_trittmattePort.port1: - pin = DigitalPin.P2; - break; - case startbit_trittmattePort.port2: - pin = DigitalPin.P14; - break; - case startbit_trittmattePort.port3: - pin = DigitalPin.P16; - break; - } +/** + * Binds code to be executed to onPulsed event + */ +//% weight=1 +//% block="Trittmatte pressed|on %port" +//% block.loc.de="Trittmatte gedrückt|auf|%port" +//% subcategory=Trittmatte +export function trittmatte_pressed( + port: startbit_trittmattePort, + handler: () => void +): void { + // handler(); + let pin: DigitalPin; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + break; + } + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); + if (pin) { pins.onPulsed(pin, PulseValue.High, handler); } +} - // MP3 Player stuff +// MP3 Player stuff - export class SongList { - TrackIndex: number; - list: Array; +export class SongList { + TrackIndex: number; + list: Array; - constructor() { - this.TrackIndex = 0; - this.list = [0]; - } + constructor() { + this.TrackIndex = 0; + this.list = [0]; + } - //% weight=99 - //% block="setze $this auf $list " - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public createSongListArray(list: number[]) { - this.list = list; - this.TrackIndex = 0; - } + //% weight=99 + //% block="setze $this auf $list " + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public createSongListArray(list: number[]) { + this.list = list; + this.TrackIndex = 0; + } - //% weight=98 - //% block="Play next track in list $this" - //% block.loc.de="nächste Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public playNextTrack() { - if (this.TrackIndex < this.list.length) { - this.TrackIndex += 1; - } else { - this.TrackIndex = 0; - } - } - // - //% weight=97 - //% block="Play previous track in list $this" - //% block.loc.de="vorherige Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public playPreviousTrack() { - if (this.TrackIndex <= 0) { - this.TrackIndex == 0; - } else { - this.TrackIndex--; - } + //% weight=98 + //% block="Play next track in list $this" + //% block.loc.de="nächste Songnummer in Liste $this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public playNextTrack() { + if (this.TrackIndex < this.list.length) { + this.TrackIndex += 1; + } else { + this.TrackIndex = 0; } - - //% weight=95 - //% block="current song number in list %this" - //% block.loc.de="Aktuelle Songnummer in liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public currentTrack(): number { - return this.list[this.TrackIndex]; + } + // + //% weight=97 + //% block="Play previous track in list $this" + //% block.loc.de="vorherige Songnummer in Liste $this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public playPreviousTrack() { + if (this.TrackIndex <= 0) { + this.TrackIndex == 0; + } else { + this.TrackIndex--; } + } - //% weight=96 - //% block="Back to first song in list %this" - //% block.loc.de="zurück zur ersten Songnummer in Liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public gotoFirstTrack() { - this.TrackIndex = 0; - } + //% weight=95 + //% block="current song number in list %this" + //% block.loc.de="Aktuelle Songnummer in liste %this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public currentTrack(): number { + return this.list[this.TrackIndex]; } - /** - * Creates a song list and automtically set it to a variable - */ - //% weight=100 - //% block="create song list" - //% block.loc.de="erstelle Songliste" - //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." - //% blockSetVariable=Songliste + //% weight=96 + //% block="Back to first song in list %this" + //% block.loc.de="zurück zur ersten Songnummer in Liste %this" + //% this.defl=Songliste + //% this.shadow=variables_get //% subcategory=MP3-Box - export function createSongList(): SongList { - return new SongList(); + public gotoFirstTrack() { + this.TrackIndex = 0; } } + +/** + * Creates a song list and automtically set it to a variable + */ +//% weight=100 +//% block="create song list" +//% block.loc.de="erstelle Songliste" +//% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." +//% blockSetVariable=Songliste +//% subcategory=MP3-Box +export function createSongList(): SongList { + return new SongList(); +} +} From e3e64bdab63927cd48ee1ff93b04d64eab20cd1e Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:44:26 +0100 Subject: [PATCH 072/253] commented missing } --- StartbitV2.ts | 202 +++++++++++++++++++++++++------------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ee2b115..579c047 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -927,119 +927,119 @@ namespace Informatiktheater { // music.playTone(440, music.beat(BeatFraction.Quarter)); // } // }); -} + // } -/** - * Binds code to be executed to onPulsed event - */ -//% weight=1 -//% block="Trittmatte pressed|on %port" -//% block.loc.de="Trittmatte gedrückt|auf|%port" -//% subcategory=Trittmatte -export function trittmatte_pressed( - port: startbit_trittmattePort, - handler: () => void -): void { - // handler(); - let pin: DigitalPin; - switch (port) { - case startbit_trittmattePort.port1: - pin = DigitalPin.P2; - break; - case startbit_trittmattePort.port2: - pin = DigitalPin.P14; - break; - case startbit_trittmattePort.port3: - pin = DigitalPin.P16; - break; - } - pins.setEvents(pin, PinEventType.Pulse); - pins.setPull(pin, PinPullMode.PullUp); - if (pin) { - pins.onPulsed(pin, PulseValue.High, handler); + /** + * Binds code to be executed to onPulsed event + */ + //% weight=1 + //% block="Trittmatte pressed|on %port" + //% block.loc.de="Trittmatte gedrückt|auf|%port" + //% subcategory=Trittmatte + export function trittmatte_pressed( + port: startbit_trittmattePort, + handler: () => void + ): void { + // handler(); + let pin: DigitalPin; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + break; + } + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); + if (pin) { + pins.onPulsed(pin, PulseValue.High, handler); + } } -} -// MP3 Player stuff + // MP3 Player stuff -export class SongList { - TrackIndex: number; - list: Array; + export class SongList { + TrackIndex: number; + list: Array; - constructor() { - this.TrackIndex = 0; - this.list = [0]; - } - - //% weight=99 - //% block="setze $this auf $list " - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public createSongListArray(list: number[]) { - this.list = list; - this.TrackIndex = 0; - } + constructor() { + this.TrackIndex = 0; + this.list = [0]; + } - //% weight=98 - //% block="Play next track in list $this" - //% block.loc.de="nächste Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public playNextTrack() { - if (this.TrackIndex < this.list.length) { - this.TrackIndex += 1; - } else { + //% weight=99 + //% block="setze $this auf $list " + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public createSongListArray(list: number[]) { + this.list = list; this.TrackIndex = 0; } - } - // - //% weight=97 - //% block="Play previous track in list $this" - //% block.loc.de="vorherige Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public playPreviousTrack() { - if (this.TrackIndex <= 0) { - this.TrackIndex == 0; - } else { - this.TrackIndex--; + + //% weight=98 + //% block="Play next track in list $this" + //% block.loc.de="nächste Songnummer in Liste $this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public playNextTrack() { + if (this.TrackIndex < this.list.length) { + this.TrackIndex += 1; + } else { + this.TrackIndex = 0; + } + } + // + //% weight=97 + //% block="Play previous track in list $this" + //% block.loc.de="vorherige Songnummer in Liste $this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public playPreviousTrack() { + if (this.TrackIndex <= 0) { + this.TrackIndex == 0; + } else { + this.TrackIndex--; + } } - } - //% weight=95 - //% block="current song number in list %this" - //% block.loc.de="Aktuelle Songnummer in liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=MP3-Box - public currentTrack(): number { - return this.list[this.TrackIndex]; + //% weight=95 + //% block="current song number in list %this" + //% block.loc.de="Aktuelle Songnummer in liste %this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public currentTrack(): number { + return this.list[this.TrackIndex]; + } + + //% weight=96 + //% block="Back to first song in list %this" + //% block.loc.de="zurück zur ersten Songnummer in Liste %this" + //% this.defl=Songliste + //% this.shadow=variables_get + //% subcategory=MP3-Box + public gotoFirstTrack() { + this.TrackIndex = 0; + } } - //% weight=96 - //% block="Back to first song in list %this" - //% block.loc.de="zurück zur ersten Songnummer in Liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get + /** + * Creates a song list and automtically set it to a variable + */ + //% weight=100 + //% block="create song list" + //% block.loc.de="erstelle Songliste" + //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." + //% blockSetVariable=Songliste //% subcategory=MP3-Box - public gotoFirstTrack() { - this.TrackIndex = 0; + export function createSongList(): SongList { + return new SongList(); } } - -/** - * Creates a song list and automtically set it to a variable - */ -//% weight=100 -//% block="create song list" -//% block.loc.de="erstelle Songliste" -//% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." -//% blockSetVariable=Songliste -//% subcategory=MP3-Box -export function createSongList(): SongList { - return new SongList(); -} -} From bbeb263797d3a1bee9569a8c8c3289f57bfdba56 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 14:58:16 +0100 Subject: [PATCH 073/253] added debug msgs --- StartbitV2.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index 579c047..e712914 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -953,10 +953,16 @@ namespace Informatiktheater { pin = DigitalPin.P16; break; } + console.log( + "Trittmatte event handler: set up pin configuration for pin " + pin + ); pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); if (pin) { + console.log("Register handler: " + handler); pins.onPulsed(pin, PulseValue.High, handler); + } else { + console.log("Error: pin not defined"); } } From 32dddcab1198e32b921c24aba76ac854fadcf689 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Feb 2023 15:40:27 +0100 Subject: [PATCH 074/253] trittmatte_released block --- StartbitV2.ts | 84 ++++++++++++++++++--------------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e712914..7aebe8a 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -884,53 +884,8 @@ namespace Informatiktheater { port3 = 0x03, } - // //% weight=100 - // //% blockId=trittmatte_init - // //% block="initialize trittmatte |%port" - // //% block.loc.de="initialisiere Trittmatte|%port" - // //% subcategory=Trittmatte - // export function trittmatte_init(port: startbit_trittmattePort) { - // let pin: DigitalPin; - // switch (port) { - // case startbit_trittmattePort.port1: - // pin = DigitalPin.P2; - // break; - // case startbit_trittmattePort.port2: - // pin = DigitalPin.P14; - // break; - // case startbit_trittmattePort.port3: - // pin = DigitalPin.P16; - // break; - // } - // pins.setEvents(pin, PinEventType.Pulse); - // pins.setPull(pin, PinPullMode.PullUp); - // - // pins.onPulsed(pin, PulseValue.High, function() { - // if (pins.pulseDuration() > 150000) { - // Informatiktheater.startbit_setPixelRGBArgs( - // StartbitLights.Light2, - // StartbitRGBColors.Orange - // ); - // Informatiktheater.startbit_showLight(); - // music.playTone(165, music.beat(BeatFraction.Quarter)); - // trittmatte_pressed(() => { }); - // } - // }); - // - // pins.onPulsed(pin, PulseValue.Low, function() { - // if (pins.pulseDuration() > 150000) { - // Informatiktheater.startbit_setPixelRGBArgs( - // StartbitLights.Light2, - // StartbitRGBColors.White - // ); - // Informatiktheater.startbit_showLight(); - // music.playTone(440, music.beat(BeatFraction.Quarter)); - // } - // }); - // } - /** - * Binds code to be executed to onPulsed event + * Binds code to be executed to onPulsed event with value high */ //% weight=1 //% block="Trittmatte pressed|on %port" @@ -940,7 +895,6 @@ namespace Informatiktheater { port: startbit_trittmattePort, handler: () => void ): void { - // handler(); let pin: DigitalPin; switch (port) { case startbit_trittmattePort.port1: @@ -953,17 +907,37 @@ namespace Informatiktheater { pin = DigitalPin.P16; break; } - console.log( - "Trittmatte event handler: set up pin configuration for pin " + pin - ); pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); - if (pin) { - console.log("Register handler: " + handler); - pins.onPulsed(pin, PulseValue.High, handler); - } else { - console.log("Error: pin not defined"); + pins.onPulsed(pin, PulseValue.High, handler); + } + + /** + * Binds code to be executed to onPulsed event with value low + */ + //% weight=1 + //% block="Trittmatte released|on %port" + //% block.loc.de="Trittmatte losgelassen|auf|%port" + //% subcategory=Trittmatte + export function trittmatte_released( + port: startbit_trittmattePort, + handler: () => void + ): void { + let pin: DigitalPin; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + break; } + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); + pins.onPulsed(pin, PulseValue.Low, handler); } // MP3 Player stuff From 5f2aee76999f0aa58c70e756a57806fde90eeb51 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 11:12:54 +0100 Subject: [PATCH 075/253] wrapper for debouncing --- StartbitV2.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 7aebe8a..1aa680c 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -208,8 +208,6 @@ namespace Informatiktheater { currentVoltage = arg3Int * 78.63; currentVoltage = Math.round(currentVoltage); } - } else if (cmd.length == 5) { - } else { } } if (cmd.charAt(0).compare("C") == 0 && cmd.length == 11) { @@ -916,8 +914,9 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value low */ //% weight=1 - //% block="Trittmatte released|on %port" - //% block.loc.de="Trittmatte losgelassen|auf|%port" + //% block="Trittmatte released|on %port |debounce time (ms) %debounce" + //% block.loc.de="Trittmatte losgelassen|auf|%port |mit Entprellzeit (ms) %debounce" + //% debounce.defl= 150 //% subcategory=Trittmatte export function trittmatte_released( port: startbit_trittmattePort, @@ -937,7 +936,12 @@ namespace Informatiktheater { } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); - pins.onPulsed(pin, PulseValue.Low, handler); + let debounce_wrapper = function() { + if (pins.pulseDuration() > 1000 * debounce) { + handler(); + } + }; + pins.onPulsed(pin, PulseValue.Low, debounce_wrapper); } // MP3 Player stuff From 6f4d22d53ce696e015b67d85ee6a64825ba31fd3 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 11:15:08 +0100 Subject: [PATCH 076/253] added missing func arg --- StartbitV2.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1aa680c..f36d3e3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -920,6 +920,7 @@ namespace Informatiktheater { //% subcategory=Trittmatte export function trittmatte_released( port: startbit_trittmattePort, + debounce: number, handler: () => void ): void { let pin: DigitalPin; From bbf12f8f131a01fc98a636b7b46d8ed698fdca1a Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 11:41:43 +0100 Subject: [PATCH 077/253] debounce wrapper for trittmatte pressed; added missing min max --- StartbitV2.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index f36d3e3..43ad19e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -886,11 +886,13 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value high */ //% weight=1 - //% block="Trittmatte pressed|on %port" - //% block.loc.de="Trittmatte gedrückt|auf|%port" + //% block="Trittmatte pressed|on %port |debounce time (ms) %debounce" + //% block.loc.de="Trittmatte gedrückt|auf|%port |mit Entprellzeit (ms) %debounce" + //% debounce.min=0 debounce.max=500 debounce.defl= 150 //% subcategory=Trittmatte export function trittmatte_pressed( port: startbit_trittmattePort, + debounce: number, handler: () => void ): void { let pin: DigitalPin; @@ -907,7 +909,12 @@ namespace Informatiktheater { } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); - pins.onPulsed(pin, PulseValue.High, handler); + let debounce_wrapper = function() { + if (pins.pulseDuration() > 1000 * debounce) { + handler(); + } + }; + pins.onPulsed(pin, PulseValue.High, debounce_wrapper); } /** @@ -916,7 +923,7 @@ namespace Informatiktheater { //% weight=1 //% block="Trittmatte released|on %port |debounce time (ms) %debounce" //% block.loc.de="Trittmatte losgelassen|auf|%port |mit Entprellzeit (ms) %debounce" - //% debounce.defl= 150 + //% debounce.min=0 debounce.max=500 debounce.defl= 150 //% subcategory=Trittmatte export function trittmatte_released( port: startbit_trittmattePort, From 5e0a9c211b5dec7adcb176fb9790aba65cffdc10 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 11:44:56 +0100 Subject: [PATCH 078/253] removed wrong whitespace defl --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 43ad19e..eee605e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -888,7 +888,7 @@ namespace Informatiktheater { //% weight=1 //% block="Trittmatte pressed|on %port |debounce time (ms) %debounce" //% block.loc.de="Trittmatte gedrückt|auf|%port |mit Entprellzeit (ms) %debounce" - //% debounce.min=0 debounce.max=500 debounce.defl= 150 + //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_pressed( port: startbit_trittmattePort, @@ -923,7 +923,7 @@ namespace Informatiktheater { //% weight=1 //% block="Trittmatte released|on %port |debounce time (ms) %debounce" //% block.loc.de="Trittmatte losgelassen|auf|%port |mit Entprellzeit (ms) %debounce" - //% debounce.min=0 debounce.max=500 debounce.defl= 150 + //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_released( port: startbit_trittmattePort, From 1238c6978fbfc444267f67357bda8a586c88bd32 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 14:18:45 +0100 Subject: [PATCH 079/253] make debounce arg collapsible --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index eee605e..b28b3c6 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -886,8 +886,8 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value high */ //% weight=1 - //% block="Trittmatte pressed|on %port |debounce time (ms) %debounce" - //% block.loc.de="Trittmatte gedrückt|auf|%port |mit Entprellzeit (ms) %debounce" + //% block="Trittmatte pressed|on %port || debounce time (ms) %debounce" + //% block.loc.de="Trittmatte gedrückt|auf|%port || mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_pressed( @@ -921,8 +921,8 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value low */ //% weight=1 - //% block="Trittmatte released|on %port |debounce time (ms) %debounce" - //% block.loc.de="Trittmatte losgelassen|auf|%port |mit Entprellzeit (ms) %debounce" + //% block="Trittmatte released|on %port || debounce time (ms) %debounce" + //% block.loc.de="Trittmatte losgelassen|auf|%port || mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_released( From 12d71ab5bd85b09965fc0e96fd834fd163dbe024 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 14:24:42 +0100 Subject: [PATCH 080/253] implicitly call show() for LED brightness / color --- StartbitV2.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b28b3c6..9445eef 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -700,6 +700,7 @@ namespace Informatiktheater { //% subcategory=LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); + lhRGBLight.show(); } //% weight=99 blockId=startbit_setPixelRGBArgs @@ -711,12 +712,9 @@ namespace Informatiktheater { rgb: StartbitRGBColors ) { lhRGBLight.setPixelColor(lightoffset, rgb); + lhRGBLight.show(); } - /** - * Display the colored lights, and set the color of the colored lights to match the use. - * After setting the color of the colored lights, the color of the lights must be displayed. - */ //% weight=97 blockId=startbit_showLight //% block="Light on" //% block.loc.de="Licht an" From 03b6c28dc2d78badaea954d335354d878c4e0efe Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 14:36:51 +0100 Subject: [PATCH 081/253] remove collapsible debounce time --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 9445eef..da3232b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -884,8 +884,8 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value high */ //% weight=1 - //% block="Trittmatte pressed|on %port || debounce time (ms) %debounce" - //% block.loc.de="Trittmatte gedrückt|auf|%port || mit Entprellzeit (ms) %debounce" + //% block="Trittmatte pressed|on %port | debounce time (ms) %debounce" + //% block.loc.de="Trittmatte gedrückt|auf|%port | mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_pressed( @@ -919,8 +919,8 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value low */ //% weight=1 - //% block="Trittmatte released|on %port || debounce time (ms) %debounce" - //% block.loc.de="Trittmatte losgelassen|auf|%port || mit Entprellzeit (ms) %debounce" + //% block="Trittmatte released|on %port | debounce time (ms) %debounce" + //% block.loc.de="Trittmatte losgelassen|auf|%port | mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte export function trittmatte_released( From ce86f497b5a2d834663cecb97f195d4a2a27e4b8 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 16:36:48 +0100 Subject: [PATCH 082/253] trittmatte on/off handler --- StartbitV2.ts | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index da3232b..6a84f81 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -883,7 +883,7 @@ namespace Informatiktheater { /** * Binds code to be executed to onPulsed event with value high */ - //% weight=1 + //% weight=9 //% block="Trittmatte pressed|on %port | debounce time (ms) %debounce" //% block.loc.de="Trittmatte gedrückt|auf|%port | mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 @@ -918,7 +918,7 @@ namespace Informatiktheater { /** * Binds code to be executed to onPulsed event with value low */ - //% weight=1 + //% weight=8 //% block="Trittmatte released|on %port | debounce time (ms) %debounce" //% block.loc.de="Trittmatte losgelassen|auf|%port | mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 @@ -950,6 +950,46 @@ namespace Informatiktheater { pins.onPulsed(pin, PulseValue.Low, debounce_wrapper); } + /** + * Binds code to be executed to onPulsed event with value high on event handler. + * The initial state will always be set to zero and the variable has local scope only! + */ + //% weight=7 + //% block="Trittmatte on/off|on %port | debounce time (ms) %debounce |state " + //% block.loc.de="Trittmatte ein/aus|auf %port | mit Entprellzeit (ms) %debounce|Status" + //% debounce.min=0 debounce.max=500 debounce.defl=150 + //% subcategory=Trittmatte + //% draggableParameters + //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" + export function trittmatte_einschalten( + port: startbit_trittmattePort, + debounce: number, + handler: (zustand: boolean) => void + ): void { + let pin: DigitalPin; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + break; + } + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); + let state = false; + let debounce_wrapper = function() { + if (pins.pulseDuration() > 1000 * debounce) { + state = !state; + handler(state); + } + }; + pins.onPulsed(pin, PulseValue.High, debounce_wrapper); + } + // MP3 Player stuff export class SongList { From d0842bff3a1f18c5c8cdfe91396101a1d2eb3cd3 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Feb 2023 16:39:33 +0100 Subject: [PATCH 083/253] renamed trittmatte status var --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 6a84f81..b4cf18f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -964,7 +964,7 @@ namespace Informatiktheater { export function trittmatte_einschalten( port: startbit_trittmattePort, debounce: number, - handler: (zustand: boolean) => void + handler: (trittmatte_ein: boolean) => void ): void { let pin: DigitalPin; switch (port) { From f0b3e7794a991d23157f5db810d6cedf338e5aaf Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Feb 2023 09:46:50 +0100 Subject: [PATCH 084/253] global vars for trittmatte --- StartbitV2.ts | 66 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b4cf18f..b754ace 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -950,41 +950,93 @@ namespace Informatiktheater { pins.onPulsed(pin, PulseValue.Low, debounce_wrapper); } + let trittmattePort1StateOn = false; + let trittmattePort2StateOn = false; + let trittmattePort3StateOn = false; + /** * Binds code to be executed to onPulsed event with value high on event handler. - * The initial state will always be set to zero and the variable has local scope only! */ //% weight=7 - //% block="Trittmatte on/off|on %port | debounce time (ms) %debounce |state " - //% block.loc.de="Trittmatte ein/aus|auf %port | mit Entprellzeit (ms) %debounce|Status" + //% block="Trittmatte switched on|on %port | debounce time (ms) %debounce" + //% block.loc.de="Trittmatte eingeschalten|auf %port | mit Entprellzeit (ms) %debounce" + //% debounce.min=0 debounce.max=500 debounce.defl=150 + //% subcategory=Trittmatte + //% draggableParameters + //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." + export function trittmatte_einschalten( + port: startbit_trittmattePort, + debounce: number, + handler: (trittmatte_ein: boolean) => void + ): void { + let pin: DigitalPin; + let globalState: boolean; + switch (port) { + case startbit_trittmattePort.port1: + pin = DigitalPin.P2; + globalState = trittmattePort1StateOn; + break; + case startbit_trittmattePort.port2: + pin = DigitalPin.P14; + globalState = trittmattePort2StateOn; + break; + case startbit_trittmattePort.port3: + pin = DigitalPin.P16; + globalState = trittmattePort3StateOn; + break; + } + pins.setEvents(pin, PinEventType.Pulse); + pins.setPull(pin, PinPullMode.PullUp); + let debounce_wrapper = function() { + if (pins.pulseDuration() > 1000 * debounce) { + if (!globalState) { + globalState = true; + handler(globalState); + } + } + }; + pins.onPulsed(pin, PulseValue.High, debounce_wrapper); + } + + /** + * Binds code to be executed to onPulsed event with value high on event handler. + */ + //% weight=8 + //% block="Trittmatte swithced off %port | debounce time (ms) %debounce" + //% block.loc.de="Trittmatte ausgeschalten|auf %port | mit Entprellzeit (ms) %debounce" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte //% draggableParameters - //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" + //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." export function trittmatte_einschalten( port: startbit_trittmattePort, debounce: number, handler: (trittmatte_ein: boolean) => void ): void { let pin: DigitalPin; + let globalState: boolean; switch (port) { case startbit_trittmattePort.port1: pin = DigitalPin.P2; + globalState = trittmattePort1StateOn; break; case startbit_trittmattePort.port2: pin = DigitalPin.P14; + globalState = trittmattePort2StateOn; break; case startbit_trittmattePort.port3: pin = DigitalPin.P16; + globalState = trittmattePort3StateOn; break; } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); - let state = false; let debounce_wrapper = function() { if (pins.pulseDuration() > 1000 * debounce) { - state = !state; - handler(state); + if (globalState) { + globalState = false; + handler(globalState); + } } }; pins.onPulsed(pin, PulseValue.High, debounce_wrapper); From 3ea791912cacecdfde7b4bca2037a4c9cffbaf0c Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Feb 2023 09:49:43 +0100 Subject: [PATCH 085/253] renamed duplicated function names --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b754ace..2909c47 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -964,7 +964,7 @@ namespace Informatiktheater { //% subcategory=Trittmatte //% draggableParameters //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." - export function trittmatte_einschalten( + export function trittmatte_on( port: startbit_trittmattePort, debounce: number, handler: (trittmatte_ein: boolean) => void @@ -1008,7 +1008,7 @@ namespace Informatiktheater { //% subcategory=Trittmatte //% draggableParameters //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." - export function trittmatte_einschalten( + export function trittmatte_off( port: startbit_trittmattePort, debounce: number, handler: (trittmatte_ein: boolean) => void From da6993a9417725a0969bb54f4eec5dd4585c5e33 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Feb 2023 11:54:54 +0100 Subject: [PATCH 086/253] Revert "global vars for trittmatte" This reverts commit f0b3e7794a991d23157f5db810d6cedf338e5aaf. --- StartbitV2.ts | 68 ++++++--------------------------------------------- 1 file changed, 8 insertions(+), 60 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 2909c47..b4cf18f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -950,93 +950,41 @@ namespace Informatiktheater { pins.onPulsed(pin, PulseValue.Low, debounce_wrapper); } - let trittmattePort1StateOn = false; - let trittmattePort2StateOn = false; - let trittmattePort3StateOn = false; - /** * Binds code to be executed to onPulsed event with value high on event handler. + * The initial state will always be set to zero and the variable has local scope only! */ //% weight=7 - //% block="Trittmatte switched on|on %port | debounce time (ms) %debounce" - //% block.loc.de="Trittmatte eingeschalten|auf %port | mit Entprellzeit (ms) %debounce" + //% block="Trittmatte on/off|on %port | debounce time (ms) %debounce |state " + //% block.loc.de="Trittmatte ein/aus|auf %port | mit Entprellzeit (ms) %debounce|Status" //% debounce.min=0 debounce.max=500 debounce.defl=150 //% subcategory=Trittmatte //% draggableParameters - //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." - export function trittmatte_on( + //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" + export function trittmatte_einschalten( port: startbit_trittmattePort, debounce: number, handler: (trittmatte_ein: boolean) => void ): void { let pin: DigitalPin; - let globalState: boolean; switch (port) { case startbit_trittmattePort.port1: pin = DigitalPin.P2; - globalState = trittmattePort1StateOn; break; case startbit_trittmattePort.port2: pin = DigitalPin.P14; - globalState = trittmattePort2StateOn; break; case startbit_trittmattePort.port3: pin = DigitalPin.P16; - globalState = trittmattePort3StateOn; break; } pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); + let state = false; let debounce_wrapper = function() { if (pins.pulseDuration() > 1000 * debounce) { - if (!globalState) { - globalState = true; - handler(globalState); - } - } - }; - pins.onPulsed(pin, PulseValue.High, debounce_wrapper); - } - - /** - * Binds code to be executed to onPulsed event with value high on event handler. - */ - //% weight=8 - //% block="Trittmatte swithced off %port | debounce time (ms) %debounce" - //% block.loc.de="Trittmatte ausgeschalten|auf %port | mit Entprellzeit (ms) %debounce" - //% debounce.min=0 debounce.max=500 debounce.defl=150 - //% subcategory=Trittmatte - //% draggableParameters - //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler." - export function trittmatte_off( - port: startbit_trittmattePort, - debounce: number, - handler: (trittmatte_ein: boolean) => void - ): void { - let pin: DigitalPin; - let globalState: boolean; - switch (port) { - case startbit_trittmattePort.port1: - pin = DigitalPin.P2; - globalState = trittmattePort1StateOn; - break; - case startbit_trittmattePort.port2: - pin = DigitalPin.P14; - globalState = trittmattePort2StateOn; - break; - case startbit_trittmattePort.port3: - pin = DigitalPin.P16; - globalState = trittmattePort3StateOn; - break; - } - pins.setEvents(pin, PinEventType.Pulse); - pins.setPull(pin, PinPullMode.PullUp); - let debounce_wrapper = function() { - if (pins.pulseDuration() > 1000 * debounce) { - if (globalState) { - globalState = false; - handler(globalState); - } + state = !state; + handler(state); } }; pins.onPulsed(pin, PulseValue.High, debounce_wrapper); From 6f72e263918152dec0f534cf79eda189574abe5d Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Feb 2023 14:09:38 +0100 Subject: [PATCH 087/253] replaced debounce time func arg as global --- StartbitV2.ts | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index b4cf18f..fd34875 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -880,17 +880,16 @@ namespace Informatiktheater { port3 = 0x03, } + let debounce_time = 150; // debounce for pin input events in [ms] /** * Binds code to be executed to onPulsed event with value high */ //% weight=9 - //% block="Trittmatte pressed|on %port | debounce time (ms) %debounce" - //% block.loc.de="Trittmatte gedrückt|auf|%port | mit Entprellzeit (ms) %debounce" - //% debounce.min=0 debounce.max=500 debounce.defl=150 + //% block="Trittmatte pressed|on %port" + //% block.loc.de="Trittmatte gedrückt|auf|%port" //% subcategory=Trittmatte export function trittmatte_pressed( port: startbit_trittmattePort, - debounce: number, handler: () => void ): void { let pin: DigitalPin; @@ -908,7 +907,7 @@ namespace Informatiktheater { pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); let debounce_wrapper = function() { - if (pins.pulseDuration() > 1000 * debounce) { + if (pins.pulseDuration() > 1000 * debounce_time) { handler(); } }; @@ -919,13 +918,11 @@ namespace Informatiktheater { * Binds code to be executed to onPulsed event with value low */ //% weight=8 - //% block="Trittmatte released|on %port | debounce time (ms) %debounce" - //% block.loc.de="Trittmatte losgelassen|auf|%port | mit Entprellzeit (ms) %debounce" - //% debounce.min=0 debounce.max=500 debounce.defl=150 + //% block="Trittmatte released|on %port" + //% block.loc.de="Trittmatte losgelassen|auf|%port" //% subcategory=Trittmatte export function trittmatte_released( port: startbit_trittmattePort, - debounce: number, handler: () => void ): void { let pin: DigitalPin; @@ -943,7 +940,7 @@ namespace Informatiktheater { pins.setEvents(pin, PinEventType.Pulse); pins.setPull(pin, PinPullMode.PullUp); let debounce_wrapper = function() { - if (pins.pulseDuration() > 1000 * debounce) { + if (pins.pulseDuration() > 1000 * debounce_time) { handler(); } }; @@ -955,15 +952,13 @@ namespace Informatiktheater { * The initial state will always be set to zero and the variable has local scope only! */ //% weight=7 - //% block="Trittmatte on/off|on %port | debounce time (ms) %debounce |state " - //% block.loc.de="Trittmatte ein/aus|auf %port | mit Entprellzeit (ms) %debounce|Status" - //% debounce.min=0 debounce.max=500 debounce.defl=150 + //% block="Trittmatte on/off|on %port |state " + //% block.loc.de="Trittmatte ein/aus|auf %port |Status" //% subcategory=Trittmatte //% draggableParameters //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" export function trittmatte_einschalten( port: startbit_trittmattePort, - debounce: number, handler: (trittmatte_ein: boolean) => void ): void { let pin: DigitalPin; @@ -982,7 +977,7 @@ namespace Informatiktheater { pins.setPull(pin, PinPullMode.PullUp); let state = false; let debounce_wrapper = function() { - if (pins.pulseDuration() > 1000 * debounce) { + if (pins.pulseDuration() > 1000 * debounce_time) { state = !state; handler(state); } From 67b803a9caed6a8a7c16bb4162072522185b6431 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 11 Mar 2023 00:07:50 +0100 Subject: [PATCH 088/253] Update StartbitV2.ts tryout in line 323 --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index fd34875..e1db871 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -320,7 +320,7 @@ namespace Informatiktheater { //% weight=100 //% blockId=setServo //% block="set servo motor %index| angle (°) %angle| duration (ms) %duration" - //% block.loc.de="setze Servomotor %index| auf Winkel (°) %angle|für Dauer (ms) %duration" + //% block.loc.de="setze Servomotor %index| auf Winkel (0 - 180°) %angle|für Dauer (ms) %duration" //% angle.min=0 angle.max=180 //% index.defl=1 //% duration.shadow=timePicker From f0e15498c40ffcad7122d027df6469921450115a Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 08:41:10 +0100 Subject: [PATCH 089/253] added neopixel library --- _locales/de/neopixel-jsdoc-strings.json | 21 + _locales/de/neopixel-strings.json | 38 ++ icon.png | Bin 22514 -> 51183 bytes neopixel.ts | 595 ++++++++++++++++++++++++ pxt.json | 24 +- 5 files changed, 673 insertions(+), 5 deletions(-) create mode 100644 _locales/de/neopixel-jsdoc-strings.json create mode 100644 _locales/de/neopixel-strings.json create mode 100644 neopixel.ts diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json new file mode 100644 index 0000000..d920989 --- /dev/null +++ b/_locales/de/neopixel-jsdoc-strings.json @@ -0,0 +1,21 @@ +{ + "neopixel.create": "Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel.", + "neopixel.Strip.showColor": "Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf.", + "neopixel.Strip.setBrigthness": "Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen.", + "neopixel.HSL.rotateHue": "Rotiert den Farbwert einer HSL-Farbe", + "neopixel.HSL.toRGB": "Konvertiert eine HSL-Farbe in eine RGB-Farbe.", + "neopixel.Strip.clear": "Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.easeBrightness": "Aktuelle Farben der NeoPixel je nach Pixelnr. abdunkeln.", + "neopixel.Strip.length": "Die Anzahl der NeoPixel, die der Treiber verwaltet.", + "neopixel.Strip.range": "Erstellt einen neuen Treiber für ein Intervall der vom angegebenen Treiber verwalteten NeoPixel.", + "neopixel.Strip.rotate": "Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.setPixelColor": "Setzt den NeoPixel mit der angegebenen Nr. auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.setPixelWhiteLED": "Setzt die Helligkeit der weißen LED des NeoPixels mit der angegebenen Nr. Dies funktioniert nur für RGB+W Neopixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.shift": "Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.showBarGraph": "Zeigt den angegebenen Wert in Bezug auf das gegebene Maximum als Balkendiagramm auf allen Neopixeln an.", + "neopixel.Strip.showRainbow": "Zeigt ein Regenbogenmuster auf allen NeoPixeln an.", + "neopixel.Strip.show": "Sendet alle Änderungen an die NeoPixel.", + "neopixel.hsl": "Erstellt eine HSL-Farbe", + "neopixel.rgb": "Erstellt eine RGB-Farbe", + "neopixel.colors": "bekannte RGB-Farben" +} diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json new file mode 100644 index 0000000..0715f8b --- /dev/null +++ b/_locales/de/neopixel-strings.json @@ -0,0 +1,38 @@ +{ + "NeoPixelColors.Black|block": "schwarz", + "NeoPixelColors.Blue|block": "blau", + "NeoPixelColors.Green|block": "grün", + "NeoPixelColors.Indigo|block": "indigo", + "NeoPixelColors.Orange|block": "orange", + "NeoPixelColors.Purple|block": "magenta", + "NeoPixelColors.Red|block": "rot", + "NeoPixelColors.Violet|block": "blauviolett", + "NeoPixelColors.White|block": "weiß", + "NeoPixelColors.Yellow|block": "gelb", + "NeoPixelMode.RGBW|block": "RGB+W", + "NeoPixelMode.RGB_RGB|block": "RGB (RGB Format)", + "NeoPixelMode.RGB|block": "RGB (GRB Format)", + "neopixel.HSL.rotateHue|block": "HSL-Farbe: rotiere Farbwert von %hsl| um %offset", + "neopixel.HSL.toRGB|block": "%hsl|nach RGB", + "neopixel.Strip.clear|block": "%strip|ausschalten", + "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", + "neopixel.Strip.length|block": "%strip|Länge", + "neopixel.Strip.range|block": "%strip|Intervall von %start|mit %length| NeoPixeln", + "neopixel.Strip.rotate|block": "%strip|rotiere NeoPixel um %offset", + "neopixel.Strip.setBrightness|block": "%strip|setze Helligkeit %brightness", + "neopixel.Strip.setPixelColor|block": "%strip|setze Farbe von NeoPixel %pixeloffset|auf %rgb=neopixel_colors", + "neopixel.Strip.setPixelWhiteLED|block": "%strip|setze weiße LED von NeoPixel %pixeloffset|auf %white", + "neopixel.Strip.shift|block": "%strip|verschiebe NeoPixel um %offset", + "neopixel.Strip.showBarGraph|block": "%strip|zeige Balkendiagramm von Wert %value |mit Maximum %high", + "neopixel.Strip.showColor|block": "%strip|zeige Farbe %rgb=neopixel_colors", + "neopixel.Strip.showRainbow|block": "%strip|zeige Regenbogen von Farbton %startHue|bis %endHue", + "neopixel.Strip.show|block": "%strip|anzeigen", + "neopixel.colors|block": "%color", + "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds|Pixeln und Modus %mode", + "neopixel.hsl|block": "HSL-Farbe: Farbwert %hue|Sättigung %sat|Helligkeit %lum", + "neopixel.Strip.power|block": "%strip|Stromverbrauch (mA)", + "neopixel.rgb|block": "rot %red|grün %green|blau %blue", + "neopixel.Strip.setMatrixColor|block": "%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors", + "neopixel.Strip.setMatrixWidth|block": "%strip|setze Matrix Breite %width", + "{id:category}Neopixel": "NeoPixel" +} diff --git a/icon.png b/icon.png index 49f3bc6de211823099e5cf37a866c9255012d64f..dea3c8ef8840baa7a5627dda84298064bbb65ec3 100644 GIT binary patch literal 51183 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 z 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


RIK{JZO1 zy>f*=`A?tV%H>NeuGVREBH}2*^AyEGz(A!;;Q3e!UJ$Zl*KYP5I>ezvhuFJ+-*>eS zar0~f9Dw<`IsWALe~;z4849Hmoo> 0; + this.setAllRGB(rgb); + this.show(); + } + + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, eg: 1 + * @param endHue the end hue value for the rainbow, eg: 360 + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% strip.defl=strip + //% weight=85 blockGap=8 + //% parts="neopixel" + showRainbow(startHue: number = 1, endHue: number = 360) { + if (this._length <= 0) return; + + startHue = startHue >> 0; + endHue = endHue >> 0; + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + + //hue + const h1 = startHue; + const h2 = endHue; + const hDistCW = ((h2 + 360) - h1) % 360; + const hStepCW = Math.idiv((hDistCW * 100), steps); + const hDistCCW = ((h1 + 360) - h2) % 360; + const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100 + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)) + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv((h1_100 + i * hStep), 100) + 360; + const s = Math.idiv((s1_100 + i * sStep), 100); + const l = Math.idiv((l1_100 + i * lStep), 100); + this.setPixelColor(i, hsl(h, s, l)); + } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); + } + this.show(); + } + + /** + * Displays a vertical bar graph based on the `value` and `high` value. + * If `high` is 0, the chart gets adjusted automatically. + * @param value current value to plot + * @param high maximum value, eg: 255 + */ + //% weight=84 + //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + //% strip.defl=strip + //% icon="\uf080" + //% parts="neopixel" + showBarGraph(value: number, high: number): void { + if (high <= 0) { + this.clear(); + this.setPixelColor(0, NeoPixelColors.Yellow); + this.show(); + return; + } + + value = Math.abs(value); + const n = this._length; + const n1 = n - 1; + let v = Math.idiv((value * n), high); + if (v == 0) { + this.setPixelColor(0, 0x666600); + for (let i = 1; i < n; ++i) + this.setPixelColor(i, 0); + } else { + for (let i = 0; i < n; ++i) { + if (i <= v) { + const b = Math.idiv(i * 255, n1); + this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); + } + else this.setPixelColor(i, 0); + } + } + this.show(); + } + + /** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_pixel_color" block="%strip|set pixel color at %pixeloffset|to %rgb=neopixel_colors" + //% strip.defl=strip + //% blockGap=8 + //% weight=80 + //% parts="neopixel" advanced=true + setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); + } + + /** + * Sets the number of pixels in a matrix shaped strip + * @param width number of pixels in a row + */ + //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" + //% strip.defl=strip + //% blockGap=8 + //% weight=5 + //% parts="neopixel" advanced=true + setMatrixWidth(width: number) { + this._matrixWidth = Math.min(this._length, width >> 0); + } + + /** + * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip + * You need to call ``show`` to make the changes visible. + * @param x horizontal position + * @param y horizontal position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=4 + //% parts="neopixel" advanced=true + setMatrixColor(x: number, y: number, rgb: number) { + if (this._matrixWidth <= 0) return; // not a matrix, ignore + x = x >> 0; + y = y >> 0; + rgb = rgb >> 0; + const cols = Math.idiv(this._length, this._matrixWidth); + if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; + let i = x + y * this._matrixWidth; + this.setPixelColor(i, rgb); + } + + /** + * For NeoPixels with RGB+W LEDs, set the white LED brightness. This only works for RGB+W NeoPixels. + * @param pixeloffset position of the LED in the strip + * @param white brightness of the white LED + */ + //% blockId="neopixel_set_pixel_white" block="%strip|set pixel white LED at %pixeloffset|to %white" + //% strip.defl=strip + //% blockGap=8 + //% weight=80 + //% parts="neopixel" advanced=true + setPixelWhiteLED(pixeloffset: number, white: number): void { + if (this._mode === NeoPixelMode.RGBW) { + this.setPixelW(pixeloffset >> 0, white >> 0); + } + } + + /** + * Send all the changes to the strip. + */ + //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% strip.defl=strip + //% weight=79 + //% parts="neopixel" + show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); + } + + /** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ + //% blockId="neopixel_clear" block="%strip|clear" + //% strip.defl=strip + //% weight=76 + //% parts="neopixel" + clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); + } + + /** + * Gets the number of pixels declared on the strip + */ + //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% strip.defl=strip + //% weight=60 advanced=true + length() { + return this._length; + } + + /** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% strip.defl=strip + //% weight=59 + //% parts="neopixel" advanced=true + setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; + } + + /** + * Apply brightness to current colors using a quadratic easing function. + **/ + //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% strip.defl=strip + //% weight=58 + //% parts="neopixel" advanced=true + easeBrightness(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const br = this.brightness; + const buf = this.buf; + const end = this.start + this._length; + const mid = Math.idiv(this._length, 2); + for (let i = this.start; i < end; ++i) { + const k = i - this.start; + const ledoffset = i * stride; + const br = k > mid + ? Math.idiv(255 * (this._length - 1 - k) * (this._length - 1 - k), (mid * mid)) + : Math.idiv(255 * k * k, (mid * mid)); + const r = (buf[ledoffset + 0] * br) >> 8; buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; buf[ledoffset + 2] = b; + if (stride == 4) { + const w = (buf[ledoffset + 3] * br) >> 8; buf[ledoffset + 3] = w; + } + } + } + + /** + * Create a range of LEDs. + * @param start offset in the LED strip to start the range + * @param length number of LEDs in the range. eg: 4 + */ + //% weight=89 + //% blockId="neopixel_range" block="%strip|range from %start|with %length|leds" + //% strip.defl=strip + //% parts="neopixel" + //% blockSetVariable=range + range(start: number, length: number): Strip { + start = start >> 0; + length = length >> 0; + let strip = new Strip(); + strip.buf = this.buf; + strip.pin = this.pin; + strip.brightness = this.brightness; + strip.start = this.start + Math.clamp(0, this._length - 1, start); + strip._length = Math.clamp(0, this._length - (strip.start - this.start), length); + strip._matrixWidth = 0; + strip._mode = this._mode; + return strip; + } + + /** + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 + */ + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=40 + //% parts="neopixel" + shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift(-offset * stride, this.start * stride, this._length * stride) + } + + /** + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 + */ + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=39 + //% parts="neopixel" + rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate(-offset * stride, this.start * stride, this._length * stride) + } + + /** + * Set the pin where the neopixel is connected, defaults to P0. + */ + //% weight=10 + //% parts="neopixel" advanced=true + setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization + } + + /** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ + //% weight=9 blockId=neopixel_power block="%strip|power (mA)" + //% strip.defl=strip + //% advanced=true + power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + const ledoffset = i * stride; + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; + } + } + return Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000); /* rought approximation */ + } + + private setBufferRGB(offset: number, red: number, green: number, blue: number): void { + if (this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; + } else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; + } + this.buf[offset + 2] = blue; + } + + private setAllRGB(rgb: number) { + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + const br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue) + } + } + private setAllW(white: number) { + if (this._mode !== NeoPixelMode.RGBW) + return; + + let br = this.brightness; + if (br < 255) { + white = (white * br) >> 8; + } + let buf = this.buf; + let end = this.start + this._length; + for (let i = this.start; i < end; ++i) { + let ledoffset = i * 4; + buf[ledoffset + 3] = white; + } + } + private setPixelRGB(pixeloffset: number, rgb: number): void { + if (pixeloffset < 0 + || pixeloffset >= this._length) + return; + + let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + pixeloffset = (pixeloffset + this.start) * stride; + + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + let br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + this.setBufferRGB(pixeloffset, red, green, blue) + } + private setPixelW(pixeloffset: number, white: number): void { + if (this._mode !== NeoPixelMode.RGBW) + return; + + if (pixeloffset < 0 + || pixeloffset >= this._length) + return; + + pixeloffset = (pixeloffset + this.start) * 4; + + let br = this.brightness; + if (br < 255) { + white = (white * br) >> 8; + } + let buf = this.buf; + buf[pixeloffset + 3] = white; + } + } + + /** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected. + * @param numleds number of leds in the strip, eg: 24,30,60,64 + */ + //% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" + //% weight=90 blockGap=8 + //% parts="neopixel" + //% trackArgs=0,2 + //% blockSetVariable=strip + export function create(pin: DigitalPin, numleds: number, mode: NeoPixelMode): Strip { + let strip = new Strip(); + let stride = mode === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB; + strip._matrixWidth = 0; + strip.setBrightness(128) + strip.setPin(pin) + return strip; + } + + /** + * Converts red, green, blue channels into a RGB color + * @param red value of the red channel between 0 and 255. eg: 255 + * @param green value of the green channel between 0 and 255. eg: 255 + * @param blue value of the blue channel between 0 and 255. eg: 255 + */ + //% weight=1 + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% advanced=true + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); + } + + /** + * Gets the RGB value of a known color + */ + //% weight=2 blockGap=8 + //% blockId="neopixel_colors" block="%color" + //% advanced=true + export function colors(color: NeoPixelColors): number { + return color; + } + + function packRGB(a: number, b: number, c: number): number { + return ((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF); + } + function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xFF; + return r; + } + function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xFF; + return g; + } + function unpackB(rgb: number): number { + let b = (rgb) & 0xFF; + return b; + } + + /** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ + //% blockId=neopixelHSL block="hue %h|saturation %s|luminosity %l" + export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv((((100 - Math.abs(2 * l - 100)) * s) << 8), 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60);//[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60);//[0,255] + let temp = Math.abs((((h1 % 2) << 8) + h2) - 256); + let x = (c * (256 - (temp))) >> 8;//[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; g$ = x; b$ = 0; + } else if (h1 == 1) { + r$ = x; g$ = c; b$ = 0; + } else if (h1 == 2) { + r$ = 0; g$ = c; b$ = x; + } else if (h1 == 3) { + r$ = 0; g$ = x; b$ = c; + } else if (h1 == 4) { + r$ = x; g$ = 0; b$ = c; + } else if (h1 == 5) { + r$ = c; g$ = 0; b$ = x; + } + let m = Math.idiv((Math.idiv((l * 2 << 8), 100) - c), 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); + } + + export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest + } +} diff --git a/pxt.json b/pxt.json index 7c11b2d..86dc6c1 100644 --- a/pxt.json +++ b/pxt.json @@ -1,18 +1,32 @@ { "name": "Informatiktheater", - "version": "0.0.2", + "version": "0.0.3", "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { - "core": "file:../core" + "core": "file:../core", + "ws2812b": "github:microsoft/pxt-ws2812b#v0.1.1" }, "files": [ "README.md", "StartbitV2.ts", "StartbitRGBLight.ts", - "sendbuffer.asm" + "sendbuffer.asm", + "neopixel.ts", + "_locales/de/neopixel-strings.json", + "_locales/de/neopixel-jsdoc-strings.json" ], - "testFiles": ["test.ts"], + "testFiles": ["test.ts", "neotest.ts"], "public": true, - "preferredEditor": "tsprj" + "supportedTargets": ["microbit"], + "preferredEditor": "tsprj", + "yotta": { + "config": { + "microbit-dal": { + "bluetooth": { + "enabled": 0 + } + } + } + } } From 091581e3cb5dd5e6b7f8690c692895f49f4c504a Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 09:23:24 +0100 Subject: [PATCH 090/253] added missing neotest.ts --- neotest.ts | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 neotest.ts diff --git a/neotest.ts b/neotest.ts new file mode 100644 index 0000000..c223e4b --- /dev/null +++ b/neotest.ts @@ -0,0 +1,82 @@ +{ + let strip = neopixel.create(DigitalPin.P0, 24, NeoPixelMode.RGB); + strip.setPixelColor(0, 0xff0000) + strip.setPixelColor(1, 0x00ff00) + strip.setPixelColor(2, 0x0000ff) + strip.show() + pause(2000) + strip.showRainbow(); + for (let i = 0; i <= strip.length(); i++) { + strip.rotate(); + strip.show(); + basic.pause(100) + } + + strip.showColor(NeoPixelColors.Red) + basic.pause(2000) + strip.showColor(NeoPixelColors.Green) + basic.pause(1000) + for (let i = 0; i <= strip.length(); i++) { + strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Blue)) + strip.show() + basic.pause(100) + } + for (let i = 0; i <= strip.length(); i++) { + strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Green)) + strip.show() + basic.pause(100) + } + let sub = strip.range(10, 20) + sub.showColor(NeoPixelColors.Yellow); + basic.pause(200); + + sub.showBarGraph(5, 10); + basic.pause(200); + + let br = 100; + strip.setBrightness(100); + input.onButtonPressed(Button.B, () => { + br = br + 20; + if (br > 255) { + br = 5; + } + strip.setBrightness(br); + }); + + let rotationMode = false; + input.onButtonPressed(Button.A, () => { + rotationMode = !rotationMode; + if (rotationMode) { + basic.showLeds(` + . # # # . + # . . . # + # . . . # + # . . . # + . # # # . + `); + } else { + basic.showLeds(` + . . # . . + . . . # . + # # # # # + . . . # . + . . # . . + `); + + } + }); + + while (true) { + let x = input.acceleration(Dimension.X) >> 1 + let y = input.acceleration(Dimension.Y) >> 1 + let z = input.acceleration(Dimension.Z) >> 1 + if (rotationMode) { + strip.rotate(); + } else { + strip.setPixelColor(0, neopixel.rgb(x, y, -z)); + strip.shift(1); + } + strip.show(); + basic.pause(100); + } +} From bbce778125316ea933101ff42f3f16d3a15e48b8 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 09:48:34 +0100 Subject: [PATCH 091/253] resolve name conflict with sendbufferasm --- StartbitRGBLight.ts | 2 +- sendbuffer.asm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index d9a21fb..c3289ab 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -60,7 +60,7 @@ enum StartbitRGBPixelMode { * QbitRGBLight Functions */ namespace StartbitRGBLight { - //% shim=sendBufferAsm + //% shim=sendBufferAsmLocale //% parts="QbitRGBLight" function sendBuffer(buf: Buffer, pin: DigitalPin) { } diff --git a/sendbuffer.asm b/sendbuffer.asm index 3ec6e87..f24cfb5 100644 --- a/sendbuffer.asm +++ b/sendbuffer.asm @@ -1,4 +1,4 @@ -sendBufferAsm: +sendBufferAsmLocale: push {r4,r5,r6,r7,lr} From ca53059f950ccfc87013c39096f6e264bdb33260 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 14:33:31 +0100 Subject: [PATCH 092/253] pixel range function --- _locales/de/neopixel-jsdoc-strings.json | 5 +- _locales/de/neopixel-strings.json | 5 +- neopixel.ts | 219 ++++++++++++------------ 3 files changed, 112 insertions(+), 117 deletions(-) diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json index d920989..b77b5b2 100644 --- a/_locales/de/neopixel-jsdoc-strings.json +++ b/_locales/de/neopixel-jsdoc-strings.json @@ -7,15 +7,12 @@ "neopixel.Strip.clear": "Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", "neopixel.Strip.easeBrightness": "Aktuelle Farben der NeoPixel je nach Pixelnr. abdunkeln.", "neopixel.Strip.length": "Die Anzahl der NeoPixel, die der Treiber verwaltet.", - "neopixel.Strip.range": "Erstellt einen neuen Treiber für ein Intervall der vom angegebenen Treiber verwalteten NeoPixel.", "neopixel.Strip.rotate": "Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.setPixelColor": "Setzt den NeoPixel mit der angegebenen Nr. auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.setPixelWhiteLED": "Setzt die Helligkeit der weißen LED des NeoPixels mit der angegebenen Nr. Dies funktioniert nur für RGB+W Neopixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", + "neopixel.Strip.setPixelColorRange": "Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", "neopixel.Strip.shift": "Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", "neopixel.Strip.showBarGraph": "Zeigt den angegebenen Wert in Bezug auf das gegebene Maximum als Balkendiagramm auf allen Neopixeln an.", "neopixel.Strip.showRainbow": "Zeigt ein Regenbogenmuster auf allen NeoPixeln an.", "neopixel.Strip.show": "Sendet alle Änderungen an die NeoPixel.", - "neopixel.hsl": "Erstellt eine HSL-Farbe", "neopixel.rgb": "Erstellt eine RGB-Farbe", "neopixel.colors": "bekannte RGB-Farben" } diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index 0715f8b..b1d7531 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -17,11 +17,9 @@ "neopixel.Strip.clear|block": "%strip|ausschalten", "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", "neopixel.Strip.length|block": "%strip|Länge", - "neopixel.Strip.range|block": "%strip|Intervall von %start|mit %length| NeoPixeln", "neopixel.Strip.rotate|block": "%strip|rotiere NeoPixel um %offset", "neopixel.Strip.setBrightness|block": "%strip|setze Helligkeit %brightness", - "neopixel.Strip.setPixelColor|block": "%strip|setze Farbe von NeoPixel %pixeloffset|auf %rgb=neopixel_colors", - "neopixel.Strip.setPixelWhiteLED|block": "%strip|setze weiße LED von NeoPixel %pixeloffset|auf %white", + "neopixel.Strip.setPixelColorRange|block": "%strip|setze Farbe(n) von %number NeoPixel(n) |an Position %pixeloffset|auf %rgb=neopixel_colors", "neopixel.Strip.shift|block": "%strip|verschiebe NeoPixel um %offset", "neopixel.Strip.showBarGraph|block": "%strip|zeige Balkendiagramm von Wert %value |mit Maximum %high", "neopixel.Strip.showColor|block": "%strip|zeige Farbe %rgb=neopixel_colors", @@ -29,7 +27,6 @@ "neopixel.Strip.show|block": "%strip|anzeigen", "neopixel.colors|block": "%color", "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds|Pixeln und Modus %mode", - "neopixel.hsl|block": "HSL-Farbe: Farbwert %hue|Sättigung %sat|Helligkeit %lum", "neopixel.Strip.power|block": "%strip|Stromverbrauch (mA)", "neopixel.rgb|block": "rot %red|grün %green|blau %blue", "neopixel.Strip.setMatrixColor|block": "%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors", diff --git a/neopixel.ts b/neopixel.ts index dd8e8f7..b2294dd 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -3,25 +3,25 @@ */ enum NeoPixelColors { //% block=red - Red = 0xFF0000, + Red = 0xff0000, //% block=orange - Orange = 0xFFA500, + Orange = 0xffa500, //% block=yellow - Yellow = 0xFFFF00, + Yellow = 0xffff00, //% block=green - Green = 0x00FF00, + Green = 0x00ff00, //% block=blue - Blue = 0x0000FF, + Blue = 0x0000ff, //% block=indigo Indigo = 0x4b0082, //% block=violet Violet = 0x8a2be2, //% block=purple - Purple = 0xFF00FF, + Purple = 0xff00ff, //% block=white - White = 0xFFFFFF, + White = 0xffffff, //% block=black - Black = 0x000000 + Black = 0x000000, } /** @@ -33,7 +33,7 @@ enum NeoPixelMode { //% block="RGB+W" RGBW = 2, //% block="RGB (RGB format)" - RGB_RGB = 3 + RGB_RGB = 3, } /** @@ -75,6 +75,8 @@ namespace neopixel { */ //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" //% strip.defl=strip + //% startHue.shadow="colorWheelPicker" + //% endHue.shadow="colorWheelPicker" //% weight=85 blockGap=8 //% parts="neopixel" showRainbow(startHue: number = 1, endHue: number = 360) { @@ -90,9 +92,9 @@ namespace neopixel { //hue const h1 = startHue; const h2 = endHue; - const hDistCW = ((h2 + 360) - h1) % 360; - const hStepCW = Math.idiv((hDistCW * 100), steps); - const hDistCCW = ((h1 + 360) - h2) % 360; + const hDistCW = (h2 + 360 - h1) % 360; + const hStepCW = Math.idiv(hDistCW * 100, steps); + const hDistCCW = (h1 + 360 - h2) % 360; const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); let hStep: number; if (direction === HueInterpolationDirection.Clockwise) { @@ -116,17 +118,17 @@ namespace neopixel { const l2 = luminance; const lDist = l2 - l1; const lStep = Math.idiv(lDist, steps); - const l1_100 = l1 * 100 + const l1_100 = l1 * 100; //interpolate if (steps === 1) { - this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)) + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); } else { this.setPixelColor(0, hsl(startHue, saturation, luminance)); for (let i = 1; i < steps - 1; i++) { - const h = Math.idiv((h1_100 + i * hStep), 100) + 360; - const s = Math.idiv((s1_100 + i * sStep), 100); - const l = Math.idiv((l1_100 + i * lStep), 100); + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); this.setPixelColor(i, hsl(h, s, l)); } this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); @@ -156,18 +158,16 @@ namespace neopixel { value = Math.abs(value); const n = this._length; const n1 = n - 1; - let v = Math.idiv((value * n), high); + let v = Math.idiv(value * n, high); if (v == 0) { this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) - this.setPixelColor(i, 0); + for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); } else { for (let i = 0; i < n; ++i) { if (i <= v) { const b = Math.idiv(i * 255, n1); this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } - else this.setPixelColor(i, 0); + } else this.setPixelColor(i, 0); } } this.show(); @@ -177,13 +177,22 @@ namespace neopixel { * Set LED to a given color (range 0-255 for r, g, b). * You need to call ``show`` to make the changes visible. * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position * @param rgb RGB color of the LED */ - //% blockId="neopixel_set_pixel_color" block="%strip|set pixel color at %pixeloffset|to %rgb=neopixel_colors" + //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" //% strip.defl=strip + //% number.defl=1 + //% number.min=1 //% blockGap=8 //% weight=80 //% parts="neopixel" advanced=true + setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + for (let i = 0; i < number; i++) { + this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + } + } + setPixelColor(pixeloffset: number, rgb: number): void { this.setPixelRGB(pixeloffset >> 0, rgb >> 0); } @@ -223,22 +232,6 @@ namespace neopixel { this.setPixelColor(i, rgb); } - /** - * For NeoPixels with RGB+W LEDs, set the white LED brightness. This only works for RGB+W NeoPixels. - * @param pixeloffset position of the LED in the strip - * @param white brightness of the white LED - */ - //% blockId="neopixel_set_pixel_white" block="%strip|set pixel white LED at %pixeloffset|to %white" - //% strip.defl=strip - //% blockGap=8 - //% weight=80 - //% parts="neopixel" advanced=true - setPixelWhiteLED(pixeloffset: number, white: number): void { - if (this._mode === NeoPixelMode.RGBW) { - this.setPixelW(pixeloffset >> 0, white >> 0); - } - } - /** * Send all the changes to the strip. */ @@ -303,42 +296,26 @@ namespace neopixel { for (let i = this.start; i < end; ++i) { const k = i - this.start; const ledoffset = i * stride; - const br = k > mid - ? Math.idiv(255 * (this._length - 1 - k) * (this._length - 1 - k), (mid * mid)) - : Math.idiv(255 * k * k, (mid * mid)); - const r = (buf[ledoffset + 0] * br) >> 8; buf[ledoffset + 0] = r; - const g = (buf[ledoffset + 1] * br) >> 8; buf[ledoffset + 1] = g; - const b = (buf[ledoffset + 2] * br) >> 8; buf[ledoffset + 2] = b; + const br = + k > mid + ? Math.idiv( + 255 * (this._length - 1 - k) * (this._length - 1 - k), + mid * mid + ) + : Math.idiv(255 * k * k, mid * mid); + const r = (buf[ledoffset + 0] * br) >> 8; + buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; + buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; + buf[ledoffset + 2] = b; if (stride == 4) { - const w = (buf[ledoffset + 3] * br) >> 8; buf[ledoffset + 3] = w; + const w = (buf[ledoffset + 3] * br) >> 8; + buf[ledoffset + 3] = w; } } } - /** - * Create a range of LEDs. - * @param start offset in the LED strip to start the range - * @param length number of LEDs in the range. eg: 4 - */ - //% weight=89 - //% blockId="neopixel_range" block="%strip|range from %start|with %length|leds" - //% strip.defl=strip - //% parts="neopixel" - //% blockSetVariable=range - range(start: number, length: number): Strip { - start = start >> 0; - length = length >> 0; - let strip = new Strip(); - strip.buf = this.buf; - strip.pin = this.pin; - strip.brightness = this.brightness; - strip.start = this.start + Math.clamp(0, this._length - 1, start); - strip._length = Math.clamp(0, this._length - (strip.start - this.start), length); - strip._matrixWidth = 0; - strip._mode = this._mode; - return strip; - } - /** * Shift LEDs forward and clear with zeros. * You need to call ``show`` to make the changes visible. @@ -351,7 +328,11 @@ namespace neopixel { shift(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.shift(-offset * stride, this.start * stride, this._length * stride) + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); } /** @@ -366,7 +347,11 @@ namespace neopixel { rotate(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.rotate(-offset * stride, this.start * stride, this._length * stride) + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); } /** @@ -396,11 +381,18 @@ namespace neopixel { p += this.buf[i + j]; } } - return Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ - + Math.idiv(p * 480, 10000); /* rought approximation */ + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ } - private setBufferRGB(offset: number, red: number, green: number, blue: number): void { + private setBufferRGB( + offset: number, + red: number, + green: number, + blue: number + ): void { if (this._mode === NeoPixelMode.RGB_RGB) { this.buf[offset + 0] = red; this.buf[offset + 1] = green; @@ -425,12 +417,11 @@ namespace neopixel { const end = this.start + this._length; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; for (let i = this.start; i < end; ++i) { - this.setBufferRGB(i * stride, red, green, blue) + this.setBufferRGB(i * stride, red, green, blue); } } private setAllW(white: number) { - if (this._mode !== NeoPixelMode.RGBW) - return; + if (this._mode !== NeoPixelMode.RGBW) return; let br = this.brightness; if (br < 255) { @@ -444,9 +435,7 @@ namespace neopixel { } } private setPixelRGB(pixeloffset: number, rgb: number): void { - if (pixeloffset < 0 - || pixeloffset >= this._length) - return; + if (pixeloffset < 0 || pixeloffset >= this._length) return; let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; pixeloffset = (pixeloffset + this.start) * stride; @@ -461,15 +450,12 @@ namespace neopixel { green = (green * br) >> 8; blue = (blue * br) >> 8; } - this.setBufferRGB(pixeloffset, red, green, blue) + this.setBufferRGB(pixeloffset, red, green, blue); } private setPixelW(pixeloffset: number, white: number): void { - if (this._mode !== NeoPixelMode.RGBW) - return; + if (this._mode !== NeoPixelMode.RGBW) return; - if (pixeloffset < 0 - || pixeloffset >= this._length) - return; + if (pixeloffset < 0 || pixeloffset >= this._length) return; pixeloffset = (pixeloffset + this.start) * 4; @@ -492,7 +478,11 @@ namespace neopixel { //% parts="neopixel" //% trackArgs=0,2 //% blockSetVariable=strip - export function create(pin: DigitalPin, numleds: number, mode: NeoPixelMode): Strip { + export function create( + pin: DigitalPin, + numleds: number, + mode: NeoPixelMode + ): Strip { let strip = new Strip(); let stride = mode === NeoPixelMode.RGBW ? 4 : 3; strip.buf = pins.createBuffer(numleds * stride); @@ -500,8 +490,8 @@ namespace neopixel { strip._length = numleds; strip._mode = mode || NeoPixelMode.RGB; strip._matrixWidth = 0; - strip.setBrightness(128) - strip.setPin(pin) + strip.setBrightness(128); + strip.setPin(pin); return strip; } @@ -520,7 +510,7 @@ namespace neopixel { /** * Gets the RGB value of a known color - */ + */ //% weight=2 blockGap=8 //% blockId="neopixel_colors" block="%color" //% advanced=true @@ -529,18 +519,18 @@ namespace neopixel { } function packRGB(a: number, b: number, c: number): number { - return ((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF); + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); } function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xFF; + let r = (rgb >> 16) & 0xff; return r; } function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xFF; + let g = (rgb >> 8) & 0xff; return g; } function unpackB(rgb: number): number { - let b = (rgb) & 0xFF; + let b = rgb & 0xff; return b; } @@ -550,7 +540,6 @@ namespace neopixel { * @param s saturation from 0 to 99 * @param l luminosity from 0 to 99 */ - //% blockId=neopixelHSL block="hue %h|saturation %s|luminosity %l" export function hsl(h: number, s: number, l: number): number { h = Math.round(h); s = Math.round(s); @@ -559,28 +548,40 @@ namespace neopixel { h = h % 360; s = Math.clamp(0, 99, s); l = Math.clamp(0, 99, l); - let c = Math.idiv((((100 - Math.abs(2 * l - 100)) * s) << 8), 10000); //chroma, [0,255] - let h1 = Math.idiv(h, 60);//[0,6] - let h2 = Math.idiv((h - h1 * 60) * 256, 60);//[0,255] - let temp = Math.abs((((h1 % 2) << 8) + h2) - 256); - let x = (c * (256 - (temp))) >> 8;//[0,255], second largest component of this color + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color let r$: number; let g$: number; let b$: number; if (h1 == 0) { - r$ = c; g$ = x; b$ = 0; + r$ = c; + g$ = x; + b$ = 0; } else if (h1 == 1) { - r$ = x; g$ = c; b$ = 0; + r$ = x; + g$ = c; + b$ = 0; } else if (h1 == 2) { - r$ = 0; g$ = c; b$ = x; + r$ = 0; + g$ = c; + b$ = x; } else if (h1 == 3) { - r$ = 0; g$ = x; b$ = c; + r$ = 0; + g$ = x; + b$ = c; } else if (h1 == 4) { - r$ = x; g$ = 0; b$ = c; + r$ = x; + g$ = 0; + b$ = c; } else if (h1 == 5) { - r$ = c; g$ = 0; b$ = x; + r$ = c; + g$ = 0; + b$ = x; } - let m = Math.idiv((Math.idiv((l * 2 << 8), 100) - c), 2); + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); let r = r$ + m; let g = g$ + m; let b = b$ + m; @@ -590,6 +591,6 @@ namespace neopixel { export enum HueInterpolationDirection { Clockwise, CounterClockwise, - Shortest + Shortest, } } From b11b16edd0c4a2503aec556f391d1423e175673d Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 16:24:34 +0100 Subject: [PATCH 093/253] removed some unused vars; re-group blocks --- neopixel.ts | 953 ++++++++++++++++++++++++++-------------------------- 1 file changed, 471 insertions(+), 482 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index b2294dd..b62f8b4 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -68,529 +68,518 @@ namespace neopixel { this.show(); } - /** - * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow, eg: 1 - * @param endHue the end hue value for the rainbow, eg: 360 - */ - //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" - //% strip.defl=strip - //% startHue.shadow="colorWheelPicker" - //% endHue.shadow="colorWheelPicker" - //% weight=85 blockGap=8 - //% parts="neopixel" - showRainbow(startHue: number = 1, endHue: number = 360) { - if (this._length <= 0) return; - - startHue = startHue >> 0; - endHue = endHue >> 0; - const saturation = 100; - const luminance = 50; - const steps = this._length; - const direction = HueInterpolationDirection.Clockwise; - - //hue - const h1 = startHue; - const h2 = endHue; - const hDistCW = (h2 + 360 - h1) % 360; - const hStepCW = Math.idiv(hDistCW * 100, steps); - const hDistCCW = (h1 + 360 - h2) % 360; - const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); - let hStep: number; - if (direction === HueInterpolationDirection.Clockwise) { - hStep = hStepCW; - } else if (direction === HueInterpolationDirection.CounterClockwise) { - hStep = hStepCCW; - } else { - hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; - } - const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation - - //sat - const s1 = saturation; - const s2 = saturation; - const sDist = s2 - s1; - const sStep = Math.idiv(sDist, steps); - const s1_100 = s1 * 100; - - //lum - const l1 = luminance; - const l2 = luminance; - const lDist = l2 - l1; - const lStep = Math.idiv(lDist, steps); - const l1_100 = l1 * 100; - - //interpolate - if (steps === 1) { - this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); - } else { - this.setPixelColor(0, hsl(startHue, saturation, luminance)); - for (let i = 1; i < steps - 1; i++) { - const h = Math.idiv(h1_100 + i * hStep, 100) + 360; - const s = Math.idiv(s1_100 + i * sStep, 100); - const l = Math.idiv(l1_100 + i * lStep, 100); - this.setPixelColor(i, hsl(h, s, l)); - } - this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); - } - this.show(); - } - /** - * Displays a vertical bar graph based on the `value` and `high` value. - * If `high` is 0, the chart gets adjusted automatically. - * @param value current value to plot - * @param high maximum value, eg: 255 - */ - //% weight=84 - //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - //% strip.defl=strip - //% icon="\uf080" - //% parts="neopixel" - showBarGraph(value: number, high: number): void { - if (high <= 0) { - this.clear(); - this.setPixelColor(0, NeoPixelColors.Yellow); - this.show(); - return; - } + /** + * Converts red, green, blue channels into a RGB color + * @param red value of the red channel between 0 and 255. eg: 255 + * @param green value of the green channel between 0 and 255. eg: 255 + * @param blue value of the blue channel between 0 and 255. eg: 255 + */ + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% weight=85 blockGap=8 + //% parts="neopixel" + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); + } - value = Math.abs(value); - const n = this._length; - const n1 = n - 1; - let v = Math.idiv(value * n, high); - if (v == 0) { - this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); - } else { - for (let i = 0; i < n; ++i) { - if (i <= v) { - const b = Math.idiv(i * 255, n1); - this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } else this.setPixelColor(i, 0); - } - } - this.show(); - } + /** + * Gets the RGB value of a known color + */ + //% blockId="neopixel_colors" block="%color" + //% weight=85 blockGap=8 + //% parts="neopixel" + export function colors(color: NeoPixelColors): number { + return color; + } - /** - * Set LED to a given color (range 0-255 for r, g, b). - * You need to call ``show`` to make the changes visible. - * @param pixeloffset position of the NeoPixel in the strip - * @param range how many pixels starting at position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" - //% strip.defl=strip - //% number.defl=1 - //% number.min=1 - //% blockGap=8 - //% weight=80 - //% parts="neopixel" advanced=true - setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { - for (let i = 0; i < number; i++) { - this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, eg: 1 + * @param endHue the end hue value for the rainbow, eg: 360 + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% strip.defl=strip + //% startHue.shadow="colorWheelPicker" + //% endHue.shadow="colorWheelPicker" + //% weight=85 blockGap=8 + //% parts="neopixel" + showRainbow(startHue: number = 1, endHue: number = 360) { + if (this._length <= 0) return; + + startHue = startHue >> 0; + endHue = endHue >> 0; + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + + //hue + const h1 = startHue; + const h2 = endHue; + const hDistCW = (h2 + 360 - h1) % 360; + const hStepCW = Math.idiv(hDistCW * 100, steps); + const hDistCCW = (h1 + 360 - h2) % 360; + const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100; + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); + this.setPixelColor(i, hsl(h, s, l)); } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); } + this.show(); + } - setPixelColor(pixeloffset: number, rgb: number): void { - this.setPixelRGB(pixeloffset >> 0, rgb >> 0); - } + /** + * Displays a vertical bar graph based on the `value` and `high` value. + * If `high` is 0, the chart gets adjusted automatically. + * @param value current value to plot + * @param high maximum value, eg: 255 + */ + //% weight=84 + //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + //% strip.defl=strip + //% icon="\uf080" + //% parts="neopixel" + showBarGraph(value: number, high: number): void { + if(high <= 0) { + this.clear(); + this.setPixelColor(0, NeoPixelColors.Yellow); + this.show(); + return; + } - /** - * Sets the number of pixels in a matrix shaped strip - * @param width number of pixels in a row - */ - //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" - //% strip.defl=strip - //% blockGap=8 - //% weight=5 - //% parts="neopixel" advanced=true - setMatrixWidth(width: number) { - this._matrixWidth = Math.min(this._length, width >> 0); + value = Math.abs(value); + const n = this._length; + const n1 = n - 1; + let v = Math.idiv(value * n, high); + if (v == 0) { + this.setPixelColor(0, 0x666600); + for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); + } else { + for (let i = 0; i < n; ++i) { + if (i <= v) { + const b = Math.idiv(i * 255, n1); + this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); + } else this.setPixelColor(i, 0); } + } + this.show(); +} - /** - * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip - * You need to call ``show`` to make the changes visible. - * @param x horizontal position - * @param y horizontal position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" - //% strip.defl=strip - //% weight=4 - //% parts="neopixel" advanced=true - setMatrixColor(x: number, y: number, rgb: number) { - if (this._matrixWidth <= 0) return; // not a matrix, ignore - x = x >> 0; - y = y >> 0; - rgb = rgb >> 0; - const cols = Math.idiv(this._length, this._matrixWidth); - if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; - let i = x + y * this._matrixWidth; - this.setPixelColor(i, rgb); +/** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position + * @param rgb RGB color of the LED + */ +//% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" +//% strip.defl=strip +//% number.defl=1 +//% number.min=1 +//% number.min=255 +//% blockGap=8 +//% weight=80 +//% parts="neopixel" advanced=true +setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + for(let i = 0; i > 0, rgb >> 0); +} } - /** - * Send all the changes to the strip. - */ - //% blockId="neopixel_show" block="%strip|show" blockGap=8 - //% strip.defl=strip - //% weight=79 - //% parts="neopixel" - show() { - // only supported in beta - // ws2812b.setBufferMode(this.pin, this._mode); - ws2812b.sendBuffer(this.buf, this.pin); - } +setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); +} - /** - * Turn off all LEDs. - * You need to call ``show`` to make the changes visible. - */ - //% blockId="neopixel_clear" block="%strip|clear" - //% strip.defl=strip - //% weight=76 - //% parts="neopixel" - clear(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.fill(0, this.start * stride, this._length * stride); - } +/** + * Sets the number of pixels in a matrix shaped strip + * @param width number of pixels in a row + */ +//% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" +//% strip.defl=strip +//% blockGap=8 +//% weight=5 +//% parts="neopixel" advanced=true +setMatrixWidth(width: number) { + this._matrixWidth = Math.min(this._length, width >> 0); +} - /** - * Gets the number of pixels declared on the strip - */ - //% blockId="neopixel_length" block="%strip|length" blockGap=8 - //% strip.defl=strip - //% weight=60 advanced=true - length() { - return this._length; - } +/** + * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip + * You need to call ``show`` to make the changes visible. + * @param x horizontal position + * @param y horizontal position + * @param rgb RGB color of the LED + */ +//% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" +//% strip.defl=strip +//% weight=4 +//% parts="neopixel" advanced=true +setMatrixColor(x: number, y: number, rgb: number) { + if (this._matrixWidth <= 0) return; // not a matrix, ignore + x = x >> 0; + y = y >> 0; + rgb = rgb >> 0; + const cols = Math.idiv(this._length, this._matrixWidth); + if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; + let i = x + y * this._matrixWidth; + this.setPixelColor(i, rgb); +} - /** - * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ - //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 - //% strip.defl=strip - //% weight=59 - //% parts="neopixel" advanced=true - setBrightness(brightness: number): void { - this.brightness = brightness & 0xff; - } +/** + * Send all the changes to the strip. + */ +//% blockId="neopixel_show" block="%strip|show" blockGap=8 +//% strip.defl=strip +//% weight=79 +//% parts="neopixel" +show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); +} - /** - * Apply brightness to current colors using a quadratic easing function. - **/ - //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 - //% strip.defl=strip - //% weight=58 - //% parts="neopixel" advanced=true - easeBrightness(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const br = this.brightness; - const buf = this.buf; - const end = this.start + this._length; - const mid = Math.idiv(this._length, 2); - for (let i = this.start; i < end; ++i) { - const k = i - this.start; - const ledoffset = i * stride; - const br = - k > mid - ? Math.idiv( - 255 * (this._length - 1 - k) * (this._length - 1 - k), - mid * mid - ) - : Math.idiv(255 * k * k, mid * mid); - const r = (buf[ledoffset + 0] * br) >> 8; - buf[ledoffset + 0] = r; - const g = (buf[ledoffset + 1] * br) >> 8; - buf[ledoffset + 1] = g; - const b = (buf[ledoffset + 2] * br) >> 8; - buf[ledoffset + 2] = b; - if (stride == 4) { - const w = (buf[ledoffset + 3] * br) >> 8; - buf[ledoffset + 3] = w; - } - } - } +/** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ +//% blockId="neopixel_clear" block="%strip|clear" +//% strip.defl=strip +//% weight=76 +//% parts="neopixel" +clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); +} - /** - * Shift LEDs forward and clear with zeros. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to shift forward, eg: 1 - */ - //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=40 - //% parts="neopixel" - shift(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.shift( - -offset * stride, - this.start * stride, - this._length * stride - ); - } +/** + * Gets the number of pixels declared on the strip + */ +//% blockId="neopixel_length" block="%strip|length" blockGap=8 +//% strip.defl=strip +//% weight=60 advanced=true +length() { + return this._length; +} - /** - * Rotate LEDs forward. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to rotate forward, eg: 1 - */ - //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=39 - //% parts="neopixel" - rotate(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.rotate( - -offset * stride, - this.start * stride, - this._length * stride - ); - } +/** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ +//% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 +//% brightness.defl=255 brightness.min=0 brightness.max=255 +//% strip.defl=strip +//% weight=59 +//% parts="neopixel" advanced=true +setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; +} - /** - * Set the pin where the neopixel is connected, defaults to P0. - */ - //% weight=10 - //% parts="neopixel" advanced=true - setPin(pin: DigitalPin): void { - this.pin = pin; - pins.digitalWritePin(this.pin, 0); - // don't yield to avoid races on initialization +/** + * Apply brightness to current colors using a quadratic easing function. + **/ +//% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 +//% strip.defl=strip +//% weight=58 +//% parts="neopixel" advanced=true +// TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? +easeBrightness(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const buf = this.buf; + const end = this.start + this._length; + const mid = Math.idiv(this._length, 2); + for(let i = this.start; i mid + ? Math.idiv( + 255 * (this._length - 1 - k) * (this._length - 1 - k), + mid * mid + ) + : Math.idiv(255 * k * k, mid * mid); + const r = (buf[ledoffset + 0] * br) >> 8; + buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; + buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; + buf[ledoffset + 2] = b; + if (stride == 4) { + const w = (buf[ledoffset + 3] * br) >> 8; + buf[ledoffset + 3] = w; + } +} } - /** - * Estimates the electrical current (mA) consumed by the current light configuration. - */ - //% weight=9 blockId=neopixel_power block="%strip|power (mA)" - //% strip.defl=strip - //% advanced=true - power(): number { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const end = this.start + this._length; - let p = 0; - for (let i = this.start; i < end; ++i) { - const ledoffset = i * stride; - for (let j = 0; j < stride; ++j) { - p += this.buf[i + j]; - } - } - return ( - Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + - Math.idiv(p * 480, 10000) - ); /* rought approximation */ +/** + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 + */ +//% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 +//% strip.defl=strip +//% weight=40 +//% parts="neopixel" +shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); +} + +/** + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 + */ +//% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 +//% strip.defl=strip +//% weight=39 +//% parts="neopixel" +rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); +} + +/** + * Set the pin where the neopixel is connected, defaults to P0. + */ +//% weight=10 +//% parts="neopixel" advanced=true +setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization +} + +/** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ +//% weight=9 blockId=neopixel_power block="%strip|power (mA)" +//% strip.defl=strip +//% advanced=true +power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; } + } + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ +} private setBufferRGB( - offset: number, - red: number, - green: number, - blue: number - ): void { - if (this._mode === NeoPixelMode.RGB_RGB) { - this.buf[offset + 0] = red; - this.buf[offset + 1] = green; - } else { - this.buf[offset + 0] = green; - this.buf[offset + 1] = red; - } - this.buf[offset + 2] = blue; + offset: number, + red: number, + green: number, + blue: number +): void { + if(this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; +} else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; +} +this.buf[offset + 2] = blue; } private setAllRGB(rgb: number) { - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - const br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - const end = this.start + this._length; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - for (let i = this.start; i < end; ++i) { - this.setBufferRGB(i * stride, red, green, blue); - } - } - private setAllW(white: number) { - if (this._mode !== NeoPixelMode.RGBW) return; - - let br = this.brightness; - if (br < 255) { - white = (white * br) >> 8; - } - let buf = this.buf; - let end = this.start + this._length; - for (let i = this.start; i < end; ++i) { - let ledoffset = i * 4; - buf[ledoffset + 3] = white; - } - } + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + const br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue); + } +} private setPixelRGB(pixeloffset: number, rgb: number): void { - if (pixeloffset < 0 || pixeloffset >= this._length) return; + if(pixeloffset < 0 || pixeloffset >= this._length) return; - let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - pixeloffset = (pixeloffset + this.start) * stride; +let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; +pixeloffset = (pixeloffset + this.start) * stride; - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); +let red = unpackR(rgb); +let green = unpackG(rgb); +let blue = unpackB(rgb); - let br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - this.setBufferRGB(pixeloffset, red, green, blue); +let br = this.brightness; +if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; +} +this.setBufferRGB(pixeloffset, red, green, blue); } private setPixelW(pixeloffset: number, white: number): void { - if (this._mode !== NeoPixelMode.RGBW) return; + if(this._mode !== NeoPixelMode.RGBW) return; - if (pixeloffset < 0 || pixeloffset >= this._length) return; + if(pixeloffset < 0 || pixeloffset >= this._length) return; - pixeloffset = (pixeloffset + this.start) * 4; +pixeloffset = (pixeloffset + this.start) * 4; - let br = this.brightness; - if (br < 255) { - white = (white * br) >> 8; - } - let buf = this.buf; - buf[pixeloffset + 3] = white; +let br = this.brightness; +if (br < 255) { + white = (white * br) >> 8; +} +let buf = this.buf; +buf[pixeloffset + 3] = white; } } - /** - * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected. - * @param numleds number of leds in the strip, eg: 24,30,60,64 - */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" - //% weight=90 blockGap=8 - //% parts="neopixel" - //% trackArgs=0,2 - //% blockSetVariable=strip - export function create( - pin: DigitalPin, - numleds: number, - mode: NeoPixelMode - ): Strip { - let strip = new Strip(); - let stride = mode === NeoPixelMode.RGBW ? 4 : 3; - strip.buf = pins.createBuffer(numleds * stride); - strip.start = 0; - strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB; - strip._matrixWidth = 0; - strip.setBrightness(128); - strip.setPin(pin); - return strip; - } - - /** - * Converts red, green, blue channels into a RGB color - * @param red value of the red channel between 0 and 255. eg: 255 - * @param green value of the green channel between 0 and 255. eg: 255 - * @param blue value of the blue channel between 0 and 255. eg: 255 - */ - //% weight=1 - //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" - //% advanced=true - export function rgb(red: number, green: number, blue: number): number { - return packRGB(red, green, blue); - } +/** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected. + * @param numleds number of leds in the strip, eg: 24,30,60,64 + */ +//% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" +//% weight=90 blockGap=8 +//% parts="neopixel" +//% trackArgs=0,2 +//% blockSetVariable=strip +export function create( + pin: DigitalPin, + numleds: number, + mode: NeoPixelMode +): Strip { + let strip = new Strip(); + let stride = mode === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB; + strip._matrixWidth = 0; + strip.setBrightness(128); + strip.setPin(pin); + return strip; +} - /** - * Gets the RGB value of a known color - */ - //% weight=2 blockGap=8 - //% blockId="neopixel_colors" block="%color" - //% advanced=true - export function colors(color: NeoPixelColors): number { - return color; - } - function packRGB(a: number, b: number, c: number): number { - return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); - } - function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xff; - return r; - } - function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xff; - return g; - } - function unpackB(rgb: number): number { - let b = rgb & 0xff; - return b; - } +function packRGB(a: number, b: number, c: number): number { + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); +} +function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xff; + return r; +} +function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xff; + return g; +} +function unpackB(rgb: number): number { + let b = rgb & 0xff; + return b; +} - /** - * Converts a hue saturation luminosity value into a RGB color - * @param h hue from 0 to 360 - * @param s saturation from 0 to 99 - * @param l luminosity from 0 to 99 - */ - export function hsl(h: number, s: number, l: number): number { - h = Math.round(h); - s = Math.round(s); - l = Math.round(l); - - h = h % 360; - s = Math.clamp(0, 99, s); - l = Math.clamp(0, 99, l); - let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] - let h1 = Math.idiv(h, 60); //[0,6] - let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] - let temp = Math.abs((h1 % 2 << 8) + h2 - 256); - let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color - let r$: number; - let g$: number; - let b$: number; - if (h1 == 0) { - r$ = c; - g$ = x; - b$ = 0; - } else if (h1 == 1) { - r$ = x; - g$ = c; - b$ = 0; - } else if (h1 == 2) { - r$ = 0; - g$ = c; - b$ = x; - } else if (h1 == 3) { - r$ = 0; - g$ = x; - b$ = c; - } else if (h1 == 4) { - r$ = x; - g$ = 0; - b$ = c; - } else if (h1 == 5) { - r$ = c; - g$ = 0; - b$ = x; - } - let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); - let r = r$ + m; - let g = g$ + m; - let b = b$ + m; - return packRGB(r, g, b); +/** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ +export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; + g$ = x; + b$ = 0; + } else if (h1 == 1) { + r$ = x; + g$ = c; + b$ = 0; + } else if (h1 == 2) { + r$ = 0; + g$ = c; + b$ = x; + } else if (h1 == 3) { + r$ = 0; + g$ = x; + b$ = c; + } else if (h1 == 4) { + r$ = x; + g$ = 0; + b$ = c; + } else if (h1 == 5) { + r$ = c; + g$ = 0; + b$ = x; } + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); +} - export enum HueInterpolationDirection { - Clockwise, - CounterClockwise, - Shortest, - } +export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest, +} } From 52ea037dbef71561bdfbb69b1cb03a539ba72e6d Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 13 Mar 2023 17:06:13 +0100 Subject: [PATCH 094/253] move back color blocks --- neopixel.ts | 938 ++++++++++++++++++++++++++-------------------------- 1 file changed, 467 insertions(+), 471 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index b62f8b4..e8a3392 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -68,518 +68,514 @@ namespace neopixel { this.show(); } - - /** - * Converts red, green, blue channels into a RGB color - * @param red value of the red channel between 0 and 255. eg: 255 - * @param green value of the green channel between 0 and 255. eg: 255 - * @param blue value of the blue channel between 0 and 255. eg: 255 - */ - //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" - //% weight=85 blockGap=8 - //% parts="neopixel" - export function rgb(red: number, green: number, blue: number): number { - return packRGB(red, green, blue); - } - - /** - * Gets the RGB value of a known color - */ - //% blockId="neopixel_colors" block="%color" - //% weight=85 blockGap=8 - //% parts="neopixel" - export function colors(color: NeoPixelColors): number { - return color; - } - - /** - * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow, eg: 1 - * @param endHue the end hue value for the rainbow, eg: 360 - */ - //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" - //% strip.defl=strip - //% startHue.shadow="colorWheelPicker" - //% endHue.shadow="colorWheelPicker" - //% weight=85 blockGap=8 - //% parts="neopixel" - showRainbow(startHue: number = 1, endHue: number = 360) { - if (this._length <= 0) return; - - startHue = startHue >> 0; - endHue = endHue >> 0; - const saturation = 100; - const luminance = 50; - const steps = this._length; - const direction = HueInterpolationDirection.Clockwise; - - //hue - const h1 = startHue; - const h2 = endHue; - const hDistCW = (h2 + 360 - h1) % 360; - const hStepCW = Math.idiv(hDistCW * 100, steps); - const hDistCCW = (h1 + 360 - h2) % 360; - const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); - let hStep: number; - if (direction === HueInterpolationDirection.Clockwise) { - hStep = hStepCW; - } else if (direction === HueInterpolationDirection.CounterClockwise) { - hStep = hStepCCW; - } else { - hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; - } - const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation - - //sat - const s1 = saturation; - const s2 = saturation; - const sDist = s2 - s1; - const sStep = Math.idiv(sDist, steps); - const s1_100 = s1 * 100; - - //lum - const l1 = luminance; - const l2 = luminance; - const lDist = l2 - l1; - const lStep = Math.idiv(lDist, steps); - const l1_100 = l1 * 100; - - //interpolate - if (steps === 1) { - this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); - } else { - this.setPixelColor(0, hsl(startHue, saturation, luminance)); - for (let i = 1; i < steps - 1; i++) { - const h = Math.idiv(h1_100 + i * hStep, 100) + 360; - const s = Math.idiv(s1_100 + i * sStep, 100); - const l = Math.idiv(l1_100 + i * lStep, 100); - this.setPixelColor(i, hsl(h, s, l)); + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, eg: 1 + * @param endHue the end hue value for the rainbow, eg: 360 + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% strip.defl=strip + //% startHue.shadow="colorWheelPicker" + //% endHue.shadow="colorWheelPicker" + //% weight=85 blockGap=8 + //% parts="neopixel" + showRainbow(startHue: number = 1, endHue: number = 360) { + if (this._length <= 0) return; + + startHue = startHue >> 0; + endHue = endHue >> 0; + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + + //hue + const h1 = startHue; + const h2 = endHue; + const hDistCW = (h2 + 360 - h1) % 360; + const hStepCW = Math.idiv(hDistCW * 100, steps); + const hDistCCW = (h1 + 360 - h2) % 360; + const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100; + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); + this.setPixelColor(i, hsl(h, s, l)); + } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); } - this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); + this.show(); } - this.show(); - } - /** - * Displays a vertical bar graph based on the `value` and `high` value. - * If `high` is 0, the chart gets adjusted automatically. - * @param value current value to plot - * @param high maximum value, eg: 255 - */ - //% weight=84 - //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - //% strip.defl=strip - //% icon="\uf080" - //% parts="neopixel" - showBarGraph(value: number, high: number): void { - if(high <= 0) { - this.clear(); - this.setPixelColor(0, NeoPixelColors.Yellow); - this.show(); - return; - } + /** + * Displays a vertical bar graph based on the `value` and `high` value. + * If `high` is 0, the chart gets adjusted automatically. + * @param value current value to plot + * @param high maximum value, eg: 255 + */ + //% weight=84 + //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + //% strip.defl=strip + //% icon="\uf080" + //% parts="neopixel" + showBarGraph(value: number, high: number): void { + if (high <= 0) { + this.clear(); + this.setPixelColor(0, NeoPixelColors.Yellow); + this.show(); + return; + } - value = Math.abs(value); - const n = this._length; - const n1 = n - 1; - let v = Math.idiv(value * n, high); - if (v == 0) { - this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); - } else { - for (let i = 0; i < n; ++i) { - if (i <= v) { - const b = Math.idiv(i * 255, n1); - this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } else this.setPixelColor(i, 0); + value = Math.abs(value); + const n = this._length; + const n1 = n - 1; + let v = Math.idiv(value * n, high); + if (v == 0) { + this.setPixelColor(0, 0x666600); + for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); + } else { + for (let i = 0; i < n; ++i) { + if (i <= v) { + const b = Math.idiv(i * 255, n1); + this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); + } else this.setPixelColor(i, 0); + } + } + this.show(); } - } - this.show(); -} -/** - * Set LED to a given color (range 0-255 for r, g, b). - * You need to call ``show`` to make the changes visible. - * @param pixeloffset position of the NeoPixel in the strip - * @param range how many pixels starting at position - * @param rgb RGB color of the LED - */ -//% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" -//% strip.defl=strip -//% number.defl=1 -//% number.min=1 -//% number.min=255 -//% blockGap=8 -//% weight=80 -//% parts="neopixel" advanced=true -setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { - for(let i = 0; i > 0, rgb >> 0); -} + /** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" + //% strip.defl=strip + //% number.defl=1 + //% number.min=1 + //% number.min=255 + //% blockGap=8 + //% weight=80 + //% parts="neopixel" advanced=true + setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + for (let i = 0; i < number; i++) { + this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + } } -setPixelColor(pixeloffset: number, rgb: number): void { - this.setPixelRGB(pixeloffset >> 0, rgb >> 0); -} + setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); + } -/** - * Sets the number of pixels in a matrix shaped strip - * @param width number of pixels in a row - */ -//% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" -//% strip.defl=strip -//% blockGap=8 -//% weight=5 -//% parts="neopixel" advanced=true -setMatrixWidth(width: number) { - this._matrixWidth = Math.min(this._length, width >> 0); -} + /** + * Sets the number of pixels in a matrix shaped strip + * @param width number of pixels in a row + */ + //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" + //% strip.defl=strip + //% blockGap=8 + //% weight=5 + //% parts="neopixel" advanced=true + setMatrixWidth(width: number) { + this._matrixWidth = Math.min(this._length, width >> 0); + } -/** - * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip - * You need to call ``show`` to make the changes visible. - * @param x horizontal position - * @param y horizontal position - * @param rgb RGB color of the LED - */ -//% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" -//% strip.defl=strip -//% weight=4 -//% parts="neopixel" advanced=true -setMatrixColor(x: number, y: number, rgb: number) { - if (this._matrixWidth <= 0) return; // not a matrix, ignore - x = x >> 0; - y = y >> 0; - rgb = rgb >> 0; - const cols = Math.idiv(this._length, this._matrixWidth); - if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; - let i = x + y * this._matrixWidth; - this.setPixelColor(i, rgb); -} + /** + * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip + * You need to call ``show`` to make the changes visible. + * @param x horizontal position + * @param y horizontal position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=4 + //% parts="neopixel" advanced=true + setMatrixColor(x: number, y: number, rgb: number) { + if (this._matrixWidth <= 0) return; // not a matrix, ignore + x = x >> 0; + y = y >> 0; + rgb = rgb >> 0; + const cols = Math.idiv(this._length, this._matrixWidth); + if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; + let i = x + y * this._matrixWidth; + this.setPixelColor(i, rgb); + } -/** - * Send all the changes to the strip. - */ -//% blockId="neopixel_show" block="%strip|show" blockGap=8 -//% strip.defl=strip -//% weight=79 -//% parts="neopixel" -show() { - // only supported in beta - // ws2812b.setBufferMode(this.pin, this._mode); - ws2812b.sendBuffer(this.buf, this.pin); -} + /** + * Send all the changes to the strip. + */ + //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% strip.defl=strip + //% weight=79 + //% parts="neopixel" + show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); + } -/** - * Turn off all LEDs. - * You need to call ``show`` to make the changes visible. - */ -//% blockId="neopixel_clear" block="%strip|clear" -//% strip.defl=strip -//% weight=76 -//% parts="neopixel" -clear(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.fill(0, this.start * stride, this._length * stride); -} + /** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ + //% blockId="neopixel_clear" block="%strip|clear" + //% strip.defl=strip + //% weight=76 + //% parts="neopixel" + clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); + } -/** - * Gets the number of pixels declared on the strip - */ -//% blockId="neopixel_length" block="%strip|length" blockGap=8 -//% strip.defl=strip -//% weight=60 advanced=true -length() { - return this._length; -} + /** + * Gets the number of pixels declared on the strip + */ + //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% strip.defl=strip + //% weight=60 advanced=true + length() { + return this._length; + } -/** - * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ -//% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 -//% brightness.defl=255 brightness.min=0 brightness.max=255 -//% strip.defl=strip -//% weight=59 -//% parts="neopixel" advanced=true -setBrightness(brightness: number): void { - this.brightness = brightness & 0xff; -} + /** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% strip.defl=strip + //% weight=59 + //% parts="neopixel" advanced=true + setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; + } -/** - * Apply brightness to current colors using a quadratic easing function. - **/ -//% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 -//% strip.defl=strip -//% weight=58 -//% parts="neopixel" advanced=true -// TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? -easeBrightness(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const buf = this.buf; - const end = this.start + this._length; - const mid = Math.idiv(this._length, 2); - for(let i = this.start; i mid - ? Math.idiv( - 255 * (this._length - 1 - k) * (this._length - 1 - k), - mid * mid - ) - : Math.idiv(255 * k * k, mid * mid); - const r = (buf[ledoffset + 0] * br) >> 8; - buf[ledoffset + 0] = r; - const g = (buf[ledoffset + 1] * br) >> 8; - buf[ledoffset + 1] = g; - const b = (buf[ledoffset + 2] * br) >> 8; - buf[ledoffset + 2] = b; - if (stride == 4) { - const w = (buf[ledoffset + 3] * br) >> 8; - buf[ledoffset + 3] = w; - } -} + /** + * Apply brightness to current colors using a quadratic easing function. + **/ + //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% strip.defl=strip + //% weight=58 + //% parts="neopixel" advanced=true + // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? + easeBrightness(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const buf = this.buf; + const end = this.start + this._length; + const mid = Math.idiv(this._length, 2); + for (let i = this.start; i < end; ++i) { + const k = i - this.start; + const ledoffset = i * stride; + const br = + k > mid + ? Math.idiv( + 255 * (this._length - 1 - k) * (this._length - 1 - k), + mid * mid + ) + : Math.idiv(255 * k * k, mid * mid); + const r = (buf[ledoffset + 0] * br) >> 8; + buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; + buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; + buf[ledoffset + 2] = b; + if (stride == 4) { + const w = (buf[ledoffset + 3] * br) >> 8; + buf[ledoffset + 3] = w; + } + } } -/** - * Shift LEDs forward and clear with zeros. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to shift forward, eg: 1 - */ -//% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 -//% strip.defl=strip -//% weight=40 -//% parts="neopixel" -shift(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.shift( - -offset * stride, - this.start * stride, - this._length * stride - ); -} + /** + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 + */ + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=40 + //% parts="neopixel" + shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); + } -/** - * Rotate LEDs forward. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to rotate forward, eg: 1 - */ -//% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 -//% strip.defl=strip -//% weight=39 -//% parts="neopixel" -rotate(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.rotate( - -offset * stride, - this.start * stride, - this._length * stride - ); -} + /** + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 + */ + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=39 + //% parts="neopixel" + rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); + } -/** - * Set the pin where the neopixel is connected, defaults to P0. - */ -//% weight=10 -//% parts="neopixel" advanced=true -setPin(pin: DigitalPin): void { - this.pin = pin; - pins.digitalWritePin(this.pin, 0); - // don't yield to avoid races on initialization -} + /** + * Set the pin where the neopixel is connected, defaults to P0. + */ + //% weight=10 + //% parts="neopixel" advanced=true + setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization + } -/** - * Estimates the electrical current (mA) consumed by the current light configuration. - */ -//% weight=9 blockId=neopixel_power block="%strip|power (mA)" -//% strip.defl=strip -//% advanced=true -power(): number { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const end = this.start + this._length; - let p = 0; - for (let i = this.start; i < end; ++i) { - for (let j = 0; j < stride; ++j) { - p += this.buf[i + j]; + /** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ + //% weight=9 blockId=neopixel_power block="%strip|power (mA)" + //% strip.defl=strip + //% advanced=true + power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; + } + } + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ } - } - return ( - Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + - Math.idiv(p * 480, 10000) - ); /* rought approximation */ -} private setBufferRGB( - offset: number, - red: number, - green: number, - blue: number -): void { - if(this._mode === NeoPixelMode.RGB_RGB) { - this.buf[offset + 0] = red; - this.buf[offset + 1] = green; -} else { - this.buf[offset + 0] = green; - this.buf[offset + 1] = red; -} -this.buf[offset + 2] = blue; + offset: number, + red: number, + green: number, + blue: number + ): void { + if (this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; + } else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; + } + this.buf[offset + 2] = blue; } private setAllRGB(rgb: number) { - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - const br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - const end = this.start + this._length; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - for (let i = this.start; i < end; ++i) { - this.setBufferRGB(i * stride, red, green, blue); - } -} + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + const br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue); + } + } private setPixelRGB(pixeloffset: number, rgb: number): void { - if(pixeloffset < 0 || pixeloffset >= this._length) return; + if (pixeloffset < 0 || pixeloffset >= this._length) return; -let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; -pixeloffset = (pixeloffset + this.start) * stride; + let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + pixeloffset = (pixeloffset + this.start) * stride; -let red = unpackR(rgb); -let green = unpackG(rgb); -let blue = unpackB(rgb); + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); -let br = this.brightness; -if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; -} -this.setBufferRGB(pixeloffset, red, green, blue); + let br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + this.setBufferRGB(pixeloffset, red, green, blue); } private setPixelW(pixeloffset: number, white: number): void { - if(this._mode !== NeoPixelMode.RGBW) return; + if (this._mode !== NeoPixelMode.RGBW) return; - if(pixeloffset < 0 || pixeloffset >= this._length) return; + if (pixeloffset < 0 || pixeloffset >= this._length) return; -pixeloffset = (pixeloffset + this.start) * 4; + pixeloffset = (pixeloffset + this.start) * 4; -let br = this.brightness; -if (br < 255) { - white = (white * br) >> 8; -} -let buf = this.buf; -buf[pixeloffset + 3] = white; + let br = this.brightness; + if (br < 255) { + white = (white * br) >> 8; + } + let buf = this.buf; + buf[pixeloffset + 3] = white; } } -/** - * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected. - * @param numleds number of leds in the strip, eg: 24,30,60,64 - */ -//% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" -//% weight=90 blockGap=8 -//% parts="neopixel" -//% trackArgs=0,2 -//% blockSetVariable=strip -export function create( - pin: DigitalPin, - numleds: number, - mode: NeoPixelMode -): Strip { - let strip = new Strip(); - let stride = mode === NeoPixelMode.RGBW ? 4 : 3; - strip.buf = pins.createBuffer(numleds * stride); - strip.start = 0; - strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB; - strip._matrixWidth = 0; - strip.setBrightness(128); - strip.setPin(pin); - return strip; -} + /** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected. + * @param numleds number of leds in the strip, eg: 24,30,60,64 + */ + //% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" + //% weight=90 blockGap=8 + //% parts="neopixel" + //% trackArgs=0,2 + //% blockSetVariable=strip + export function create( + pin: DigitalPin, + numleds: number, + mode: NeoPixelMode + ): Strip { + let strip = new Strip(); + let stride = mode === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB; + strip._matrixWidth = 0; + strip.setBrightness(128); + strip.setPin(pin); + return strip; + } + /** + * Converts red, green, blue channels into a RGB color + * @param red value of the red channel between 0 and 255. eg: 255 + * @param green value of the green channel between 0 and 255. eg: 255 + * @param blue value of the blue channel between 0 and 255. eg: 255 + */ + //% weight=85 blockGap=8 + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); + } -function packRGB(a: number, b: number, c: number): number { - return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); -} -function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xff; - return r; -} -function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xff; - return g; -} -function unpackB(rgb: number): number { - let b = rgb & 0xff; - return b; -} + /** + * Gets the RGB value of a known color + */ + //% weight=85 blockGap=8 + //% blockId="neopixel_colors" block="%color" + export function colors(color: NeoPixelColors): number { + return color; + } -/** - * Converts a hue saturation luminosity value into a RGB color - * @param h hue from 0 to 360 - * @param s saturation from 0 to 99 - * @param l luminosity from 0 to 99 - */ -export function hsl(h: number, s: number, l: number): number { - h = Math.round(h); - s = Math.round(s); - l = Math.round(l); - - h = h % 360; - s = Math.clamp(0, 99, s); - l = Math.clamp(0, 99, l); - let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] - let h1 = Math.idiv(h, 60); //[0,6] - let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] - let temp = Math.abs((h1 % 2 << 8) + h2 - 256); - let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color - let r$: number; - let g$: number; - let b$: number; - if (h1 == 0) { - r$ = c; - g$ = x; - b$ = 0; - } else if (h1 == 1) { - r$ = x; - g$ = c; - b$ = 0; - } else if (h1 == 2) { - r$ = 0; - g$ = c; - b$ = x; - } else if (h1 == 3) { - r$ = 0; - g$ = x; - b$ = c; - } else if (h1 == 4) { - r$ = x; - g$ = 0; - b$ = c; - } else if (h1 == 5) { - r$ = c; - g$ = 0; - b$ = x; + function packRGB(a: number, b: number, c: number): number { + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); + } + function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xff; + return r; + } + function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xff; + return g; + } + function unpackB(rgb: number): number { + let b = rgb & 0xff; + return b; } - let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); - let r = r$ + m; - let g = g$ + m; - let b = b$ + m; - return packRGB(r, g, b); -} -export enum HueInterpolationDirection { - Clockwise, - CounterClockwise, - Shortest, -} + /** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ + export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; + g$ = x; + b$ = 0; + } else if (h1 == 1) { + r$ = x; + g$ = c; + b$ = 0; + } else if (h1 == 2) { + r$ = 0; + g$ = c; + b$ = x; + } else if (h1 == 3) { + r$ = 0; + g$ = x; + b$ = c; + } else if (h1 == 4) { + r$ = x; + g$ = 0; + b$ = c; + } else if (h1 == 5) { + r$ = c; + g$ = 0; + b$ = x; + } + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); + } + + export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest, + } } From 33dec29c31eefbf2a087e53c49dbb63302a62951 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 08:32:17 +0100 Subject: [PATCH 095/253] sliders for color value selections --- neopixel.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index e8a3392..dd60dbf 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -490,6 +490,9 @@ namespace neopixel { */ //% weight=85 blockGap=8 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% red.defl=255 red.min=0 red.max=255 + //% blue.defl=255 blue.min=0 blue.max=255 + //% green.defl=255 green.min=0 green.max=255 export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); } From d7b9bdf96580d80fef4561c537e7c856c7438d84 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 11:27:36 +0100 Subject: [PATCH 096/253] Stripe & Matrix categories; HSV instead of RGB color picker and correction for rainbow --- neopixel.ts | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index dd60dbf..6e95ad8 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -62,6 +62,7 @@ namespace neopixel { //% strip.defl=strip //% weight=85 blockGap=8 //% parts="neopixel" + //% subcategory=Stripe showColor(rgb: number) { rgb = rgb >> 0; this.setAllRGB(rgb); @@ -70,20 +71,23 @@ namespace neopixel { /** * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow, eg: 1 - * @param endHue the end hue value for the rainbow, eg: 360 + * @param startHue the start hue value for the rainbow + * @param endHue the end hue value for the rainbow */ //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" //% strip.defl=strip - //% startHue.shadow="colorWheelPicker" - //% endHue.shadow="colorWheelPicker" + //% startHue.shadow="colorWheelHsvPicker" + //% endHue.shadow="colorWheelHsvPicker" //% weight=85 blockGap=8 //% parts="neopixel" - showRainbow(startHue: number = 1, endHue: number = 360) { + //% subcategory=Stripe + showRainbow(startHue: number = 1, endHue: number = 255) { if (this._length <= 0) return; startHue = startHue >> 0; + startHue = (startHue * 360) / 255; endHue = endHue >> 0; + endHue = (endHue * 360) / 255; const saturation = 100; const luminance = 50; const steps = this._length; @@ -147,6 +151,7 @@ namespace neopixel { //% strip.defl=strip //% icon="\uf080" //% parts="neopixel" + //% subcategory=Stripe showBarGraph(value: number, high: number): void { if (high <= 0) { this.clear(); @@ -187,7 +192,8 @@ namespace neopixel { //% number.min=255 //% blockGap=8 //% weight=80 - //% parts="neopixel" advanced=true + //% parts="neopixel" + //% subcategory=Stripe setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { for (let i = 0; i < number; i++) { this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); @@ -206,7 +212,8 @@ namespace neopixel { //% strip.defl=strip //% blockGap=8 //% weight=5 - //% parts="neopixel" advanced=true + //% parts="neopixel" + //% subcategory=Matrix setMatrixWidth(width: number) { this._matrixWidth = Math.min(this._length, width >> 0); } @@ -221,7 +228,8 @@ namespace neopixel { //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" //% strip.defl=strip //% weight=4 - //% parts="neopixel" advanced=true + //% parts="neopixel" + //% subcategory=Matrix setMatrixColor(x: number, y: number, rgb: number) { if (this._matrixWidth <= 0) return; // not a matrix, ignore x = x >> 0; @@ -240,6 +248,7 @@ namespace neopixel { //% strip.defl=strip //% weight=79 //% parts="neopixel" + //% subcategory=Stripe show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); @@ -254,6 +263,7 @@ namespace neopixel { //% strip.defl=strip //% weight=76 //% parts="neopixel" + //% subcategory=Stripe clear(): void { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; this.buf.fill(0, this.start * stride, this._length * stride); @@ -264,7 +274,8 @@ namespace neopixel { */ //% blockId="neopixel_length" block="%strip|length" blockGap=8 //% strip.defl=strip - //% weight=60 advanced=true + //% weight=60 + //% subcategory=Stripe length() { return this._length; } @@ -277,7 +288,8 @@ namespace neopixel { //% brightness.defl=255 brightness.min=0 brightness.max=255 //% strip.defl=strip //% weight=59 - //% parts="neopixel" advanced=true + //% parts="neopixel" + //% subcategory=Stripe setBrightness(brightness: number): void { this.brightness = brightness & 0xff; } @@ -288,8 +300,9 @@ namespace neopixel { //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 //% strip.defl=strip //% weight=58 - //% parts="neopixel" advanced=true - // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? + //% parts="neopixel" + //% subcategory=Stripe + // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? easeBrightness(): void { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; const buf = this.buf; @@ -327,6 +340,7 @@ namespace neopixel { //% strip.defl=strip //% weight=40 //% parts="neopixel" + //% subcategory=Stripe shift(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; @@ -346,6 +360,7 @@ namespace neopixel { //% strip.defl=strip //% weight=39 //% parts="neopixel" + //% subcategory=Stripe rotate(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; @@ -360,7 +375,8 @@ namespace neopixel { * Set the pin where the neopixel is connected, defaults to P0. */ //% weight=10 - //% parts="neopixel" advanced=true + //% parts="neopixel" + //% subcategory=Stripe setPin(pin: DigitalPin): void { this.pin = pin; pins.digitalWritePin(this.pin, 0); @@ -372,7 +388,7 @@ namespace neopixel { */ //% weight=9 blockId=neopixel_power block="%strip|power (mA)" //% strip.defl=strip - //% advanced=true + //% subcategory=Stripe power(): number { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; const end = this.start + this._length; @@ -463,6 +479,7 @@ namespace neopixel { //% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" //% weight=90 blockGap=8 //% parts="neopixel" + //% subcategory=Stripe //% trackArgs=0,2 //% blockSetVariable=strip export function create( @@ -483,10 +500,8 @@ namespace neopixel { } /** - * Converts red, green, blue channels into a RGB color - * @param red value of the red channel between 0 and 255. eg: 255 - * @param green value of the green channel between 0 and 255. eg: 255 - * @param blue value of the blue channel between 0 and 255. eg: 255 + * Selects a color from color picker + * @param */ //% weight=85 blockGap=8 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" From 6c619193a5ceae9388668bae391256fcd2a2d77d Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 11:32:20 +0100 Subject: [PATCH 097/253] rename to Hiwonder LED --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e1db871..dee23c2 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -697,7 +697,7 @@ namespace Informatiktheater { //% jsdoc.loc.de="Setze die Hellighkeit des LED Streifens. Dies gilt nur zukünftige Operationen." //% brightness.loc.de="LED Helligkeit zwischen 0 bis 255" //% weight=100 - //% subcategory=LED + //% subcategory=Hiwonder LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); lhRGBLight.show(); @@ -706,7 +706,7 @@ namespace Informatiktheater { //% weight=99 blockId=startbit_setPixelRGBArgs //% block="set|%lightoffset|color to %rgb" //% block.loc.de="setze Farbe von|%lightoffset|auf %rgb" - //% subcategory=LED + //% subcategory=Hiwonder LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, rgb: StartbitRGBColors @@ -719,7 +719,7 @@ namespace Informatiktheater { //% block="Light on" //% block.loc.de="Licht an" //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" - //% subcategory=LED + //% subcategory=Hiwonder LED export function startbit_showLight() { lhRGBLight.show(); } @@ -731,7 +731,7 @@ namespace Informatiktheater { //% block="Light off" //% block.loc.de="Licht aus" //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" - //% subcategory=LED + //% subcategory=Hiwonder LED export function startbit_clearLight() { lhRGBLight.clear(); } From 038a8f4a4357b7c5ece0e265fba17e982aa3e90a Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 11:56:21 +0100 Subject: [PATCH 098/253] log hue values --- neopixel.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 6e95ad8..3691e61 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -84,10 +84,11 @@ namespace neopixel { showRainbow(startHue: number = 1, endHue: number = 255) { if (this._length <= 0) return; - startHue = startHue >> 0; + console.log("startHue:" + startHue + "\nEndHue:" + endHue); startHue = (startHue * 360) / 255; - endHue = endHue >> 0; + startHue = startHue >> 0; endHue = (endHue * 360) / 255; + endHue = endHue >> 0; const saturation = 100; const luminance = 50; const steps = this._length; From 62298cb003a98b27043d4b0ba9a1bdf492225cb1 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 12:01:06 +0100 Subject: [PATCH 099/253] log hue values --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 3691e61..bfa1876 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -84,11 +84,11 @@ namespace neopixel { showRainbow(startHue: number = 1, endHue: number = 255) { if (this._length <= 0) return; - console.log("startHue:" + startHue + "\nEndHue:" + endHue); startHue = (startHue * 360) / 255; startHue = startHue >> 0; endHue = (endHue * 360) / 255; endHue = endHue >> 0; + console.log("startHue:" + startHue + "\nEndHue:" + endHue); const saturation = 100; const luminance = 50; const steps = this._length; From ce8611b13301b62d28d5ad39aed70be0d221e919 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 13:42:36 +0100 Subject: [PATCH 100/253] hstep log --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index bfa1876..4066209 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -88,7 +88,6 @@ namespace neopixel { startHue = startHue >> 0; endHue = (endHue * 360) / 255; endHue = endHue >> 0; - console.log("startHue:" + startHue + "\nEndHue:" + endHue); const saturation = 100; const luminance = 50; const steps = this._length; @@ -109,6 +108,7 @@ namespace neopixel { } else { hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; } + console.log("hstep= " + hStep); const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation //sat From 97602fe4c78d770748c88eaaa3e0dbcacca49957 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 13:49:16 +0100 Subject: [PATCH 101/253] HueInterpolationDirection value check --- neopixel.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 4066209..d97e3ee 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -91,7 +91,12 @@ namespace neopixel { const saturation = 100; const luminance = 50; const steps = this._length; - const direction = HueInterpolationDirection.Clockwise; + let direction; + if (endHue > startHue) { + direction = HueInterpolationDirection.Clockwise; + } else if (endHue < startHue) { + direction = HueInterpolationDirection.CounterClockwise; + } //hue const h1 = startHue; From 5a2ec36562072cd7cd07473bbd3d1f3630fff267 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 14:09:27 +0100 Subject: [PATCH 102/253] check for full rainbow --- neopixel.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index d97e3ee..c27c677 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -101,11 +101,23 @@ namespace neopixel { //hue const h1 = startHue; const h2 = endHue; - const hDistCW = (h2 + 360 - h1) % 360; - const hStepCW = Math.idiv(hDistCW * 100, steps); - const hDistCCW = (h1 + 360 - h2) % 360; - const hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hDistCW; + let hDistCCW; + let hStepCW; + let hStepCCW; + + // In case we have a full rainbow + if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { + hDistCW = 360; + hDistCCW = 360; + } else { + hDistCW = (h2 + 360 - h1) % 360; + hDistCCW = (h1 + 360 - h2) % 360; + } + hStepCW = Math.idiv(hDistCW * 100, steps); + hStepCCW = Math.idiv(-(hDistCCW * 100), steps); let hStep: number; + if (direction === HueInterpolationDirection.Clockwise) { hStep = hStepCW; } else if (direction === HueInterpolationDirection.CounterClockwise) { @@ -113,7 +125,7 @@ namespace neopixel { } else { hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; } - console.log("hstep= " + hStep); + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation //sat From 08f4978d43722203f9a2a112247271c6e1282bae Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 14:22:01 +0100 Subject: [PATCH 103/253] remove unused blocks from locales --- _locales/de/neopixel-jsdoc-strings.json | 4 +--- _locales/de/neopixel-strings.json | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json index b77b5b2..f50a889 100644 --- a/_locales/de/neopixel-jsdoc-strings.json +++ b/_locales/de/neopixel-jsdoc-strings.json @@ -1,9 +1,7 @@ { "neopixel.create": "Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel.", "neopixel.Strip.showColor": "Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf.", - "neopixel.Strip.setBrigthness": "Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen.", - "neopixel.HSL.rotateHue": "Rotiert den Farbwert einer HSL-Farbe", - "neopixel.HSL.toRGB": "Konvertiert eine HSL-Farbe in eine RGB-Farbe.", + "neopixel.Strip.setBrightness": "Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen.", "neopixel.Strip.clear": "Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", "neopixel.Strip.easeBrightness": "Aktuelle Farben der NeoPixel je nach Pixelnr. abdunkeln.", "neopixel.Strip.length": "Die Anzahl der NeoPixel, die der Treiber verwaltet.", diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index b1d7531..98edf23 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -12,8 +12,6 @@ "NeoPixelMode.RGBW|block": "RGB+W", "NeoPixelMode.RGB_RGB|block": "RGB (RGB Format)", "NeoPixelMode.RGB|block": "RGB (GRB Format)", - "neopixel.HSL.rotateHue|block": "HSL-Farbe: rotiere Farbwert von %hsl| um %offset", - "neopixel.HSL.toRGB|block": "%hsl|nach RGB", "neopixel.Strip.clear|block": "%strip|ausschalten", "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", "neopixel.Strip.length|block": "%strip|Länge", From 10b55f328ad1e587f3855c4b300ef83a04080a6f Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 14:53:14 +0100 Subject: [PATCH 104/253] compensate difference in start value for hsv color picker --- neopixel.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index c27c677..606d539 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -88,6 +88,11 @@ namespace neopixel { startHue = startHue >> 0; endHue = (endHue * 360) / 255; endHue = endHue >> 0; + + // compensate for difference of start color in HSV color wheel picker + startHue -= 120; + endHue -= 120; + const saturation = 100; const luminance = 50; const steps = this._length; From 4a3213facd0d9e86fdde277eb64d88b2960c3389 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 15:03:30 +0100 Subject: [PATCH 105/253] keep direction alway clockwise --- neopixel.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 606d539..000ec1f 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -96,12 +96,12 @@ namespace neopixel { const saturation = 100; const luminance = 50; const steps = this._length; - let direction; - if (endHue > startHue) { - direction = HueInterpolationDirection.Clockwise; - } else if (endHue < startHue) { - direction = HueInterpolationDirection.CounterClockwise; - } + const direction = HueInterpolationDirection.Clockwise; + // if (endHue > startHue) { + // direction = HueInterpolationDirection.Clockwise; + // } else if (endHue < startHue) { + // direction = HueInterpolationDirection.CounterClockwise; + // } //hue const h1 = startHue; From a81324f6fbef19f959f23bd8ae86d85c8b3a62ea Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 15:06:08 +0100 Subject: [PATCH 106/253] log estimated current consumption --- neopixel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/neopixel.ts b/neopixel.ts index 000ec1f..56418e7 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -276,6 +276,7 @@ namespace neopixel { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); ws2812b.sendBuffer(this.buf, this.pin); + console.log("Estimated current for neopixels = " + power()); } /** From 08fd3a569d5063cce2dbd12ff6441a92c8c50305 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 14 Mar 2023 15:16:56 +0100 Subject: [PATCH 107/253] this.power --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 56418e7..6b506c8 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -276,7 +276,7 @@ namespace neopixel { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); ws2812b.sendBuffer(this.buf, this.pin); - console.log("Estimated current for neopixels = " + power()); + console.log("Estimated current for neopixels = " + this.power()); } /** From 333f780d89b80fb794547356b9ae25b5ddadd8d0 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 13:10:47 +0100 Subject: [PATCH 108/253] renaming to onboard-led --- StartbitV2.ts | 8 ++++---- _locales/de/neopixel-strings.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index dee23c2..4a11b4f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -697,7 +697,7 @@ namespace Informatiktheater { //% jsdoc.loc.de="Setze die Hellighkeit des LED Streifens. Dies gilt nur zukünftige Operationen." //% brightness.loc.de="LED Helligkeit zwischen 0 bis 255" //% weight=100 - //% subcategory=Hiwonder LED + //% subcategory=Onboard-LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); lhRGBLight.show(); @@ -706,7 +706,7 @@ namespace Informatiktheater { //% weight=99 blockId=startbit_setPixelRGBArgs //% block="set|%lightoffset|color to %rgb" //% block.loc.de="setze Farbe von|%lightoffset|auf %rgb" - //% subcategory=Hiwonder LED + //% subcategory=Onboard-LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, rgb: StartbitRGBColors @@ -719,7 +719,7 @@ namespace Informatiktheater { //% block="Light on" //% block.loc.de="Licht an" //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" - //% subcategory=Hiwonder LED + //% subcategory=Onboard-LED export function startbit_showLight() { lhRGBLight.show(); } @@ -731,7 +731,7 @@ namespace Informatiktheater { //% block="Light off" //% block.loc.de="Licht aus" //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" - //% subcategory=Hiwonder LED + //% subcategory=Onboard-LED export function startbit_clearLight() { lhRGBLight.clear(); } diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index 98edf23..e9754bd 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -10,8 +10,8 @@ "NeoPixelColors.White|block": "weiß", "NeoPixelColors.Yellow|block": "gelb", "NeoPixelMode.RGBW|block": "RGB+W", - "NeoPixelMode.RGB_RGB|block": "RGB (RGB Format)", - "NeoPixelMode.RGB|block": "RGB (GRB Format)", + "NeoPixelMode.RGB_RGB|block": "RGB", + "NeoPixelMode.RGB|block": "GRB", "neopixel.Strip.clear|block": "%strip|ausschalten", "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", "neopixel.Strip.length|block": "%strip|Länge", From 0536119baa333707a0c779ac7c8c8fb90b8cf208 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 13:21:04 +0100 Subject: [PATCH 109/253] fix GRB mode --- _locales/de/neopixel-strings.json | 4 +-- neopixel.ts | 14 ++++----- neotest.ts | 47 +++++++++++++++---------------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index e9754bd..e9df320 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -11,7 +11,7 @@ "NeoPixelColors.Yellow|block": "gelb", "NeoPixelMode.RGBW|block": "RGB+W", "NeoPixelMode.RGB_RGB|block": "RGB", - "NeoPixelMode.RGB|block": "GRB", + "NeoPixelMode.RGB_GRB|block": "GRB", "neopixel.Strip.clear|block": "%strip|ausschalten", "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", "neopixel.Strip.length|block": "%strip|Länge", @@ -24,7 +24,7 @@ "neopixel.Strip.showRainbow|block": "%strip|zeige Regenbogen von Farbton %startHue|bis %endHue", "neopixel.Strip.show|block": "%strip|anzeigen", "neopixel.colors|block": "%color", - "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds|Pixeln und Modus %mode", + "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds Pixeln", "neopixel.Strip.power|block": "%strip|Stromverbrauch (mA)", "neopixel.rgb|block": "rot %red|grün %green|blau %blue", "neopixel.Strip.setMatrixColor|block": "%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors", diff --git a/neopixel.ts b/neopixel.ts index 6b506c8..3efe013 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -29,7 +29,7 @@ enum NeoPixelColors { */ enum NeoPixelMode { //% block="RGB (GRB format)" - RGB = 1, + RGB_GRB = 1, //% block="RGB+W" RGBW = 2, //% block="RGB (RGB format)" @@ -479,6 +479,7 @@ namespace neopixel { } this.setBufferRGB(pixeloffset, red, green, blue); } + private setPixelW(pixeloffset: number, white: number): void { if (this._mode !== NeoPixelMode.RGBW) return; @@ -500,23 +501,20 @@ namespace neopixel { * @param pin the pin where the neopixel is connected. * @param numleds number of leds in the strip, eg: 24,30,60,64 */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin|with %numleds|leds as %mode" + //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" //% weight=90 blockGap=8 //% parts="neopixel" //% subcategory=Stripe //% trackArgs=0,2 //% blockSetVariable=strip - export function create( - pin: DigitalPin, - numleds: number, - mode: NeoPixelMode - ): Strip { + export function create(pin: DigitalPin, numleds: number): Strip { let strip = new Strip(); + let mode: NeoPixelMode = NeoPixelMode.RGB_GRB; let stride = mode === NeoPixelMode.RGBW ? 4 : 3; strip.buf = pins.createBuffer(numleds * stride); strip.start = 0; strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB; + strip._mode = mode || NeoPixelMode.RGB_GRB; strip._matrixWidth = 0; strip.setBrightness(128); strip.setPin(pin); diff --git a/neotest.ts b/neotest.ts index c223e4b..1bdb08d 100644 --- a/neotest.ts +++ b/neotest.ts @@ -1,32 +1,32 @@ { - let strip = neopixel.create(DigitalPin.P0, 24, NeoPixelMode.RGB); - strip.setPixelColor(0, 0xff0000) - strip.setPixelColor(1, 0x00ff00) - strip.setPixelColor(2, 0x0000ff) - strip.show() - pause(2000) + let strip = neopixel.create(DigitalPin.P0, 24, NeoPixelMode.RGB_GRB); + strip.setPixelColor(0, 0xff0000); + strip.setPixelColor(1, 0x00ff00); + strip.setPixelColor(2, 0x0000ff); + strip.show(); + pause(2000); strip.showRainbow(); - for (let i = 0; i <= strip.length(); i++) { + for (let i = 0; i <= strip.length(); i++) { strip.rotate(); strip.show(); - basic.pause(100) + basic.pause(100); } - - strip.showColor(NeoPixelColors.Red) - basic.pause(2000) - strip.showColor(NeoPixelColors.Green) - basic.pause(1000) + + strip.showColor(NeoPixelColors.Red); + basic.pause(2000); + strip.showColor(NeoPixelColors.Green); + basic.pause(1000); for (let i = 0; i <= strip.length(); i++) { - strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Blue)) - strip.show() - basic.pause(100) + strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Blue)); + strip.show(); + basic.pause(100); } for (let i = 0; i <= strip.length(); i++) { - strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Green)) - strip.show() - basic.pause(100) + strip.setPixelColor(i, neopixel.colors(NeoPixelColors.Green)); + strip.show(); + basic.pause(100); } - let sub = strip.range(10, 20) + let sub = strip.range(10, 20); sub.showColor(NeoPixelColors.Yellow); basic.pause(200); @@ -62,14 +62,13 @@ . . . # . . . # . . `); - } }); while (true) { - let x = input.acceleration(Dimension.X) >> 1 - let y = input.acceleration(Dimension.Y) >> 1 - let z = input.acceleration(Dimension.Z) >> 1 + let x = input.acceleration(Dimension.X) >> 1; + let y = input.acceleration(Dimension.Y) >> 1; + let z = input.acceleration(Dimension.Z) >> 1; if (rotationMode) { strip.rotate(); } else { From aeba1ffbefcaa2fbacf4307cf2d412e8e343065b Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 13:28:18 +0100 Subject: [PATCH 110/253] remove rainbow angle shift which was caused by wrong RGB mode --- neopixel.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 3efe013..7967542 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -71,7 +71,7 @@ namespace neopixel { /** * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow + * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red * @param endHue the end hue value for the rainbow */ //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" @@ -89,10 +89,6 @@ namespace neopixel { endHue = (endHue * 360) / 255; endHue = endHue >> 0; - // compensate for difference of start color in HSV color wheel picker - startHue -= 120; - endHue -= 120; - const saturation = 100; const luminance = 50; const steps = this._length; From a4441a7090ef4fbd7b7c33e8fb8b4c82a9746c7f Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 13:44:04 +0100 Subject: [PATCH 111/253] enum starting at 2 --- neopixel.ts | 1120 +++++++++++++++++++++++++-------------------------- 1 file changed, 560 insertions(+), 560 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 7967542..c4d2b57 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -2,38 +2,38 @@ * Well known colors for a NeoPixel strip */ enum NeoPixelColors { - //% block=red - Red = 0xff0000, - //% block=orange - Orange = 0xffa500, - //% block=yellow - Yellow = 0xffff00, - //% block=green - Green = 0x00ff00, - //% block=blue - Blue = 0x0000ff, - //% block=indigo - Indigo = 0x4b0082, - //% block=violet - Violet = 0x8a2be2, - //% block=purple - Purple = 0xff00ff, - //% block=white - White = 0xffffff, - //% block=black - Black = 0x000000, + //% block=red + Red = 0xff0000, + //% block=orange + Orange = 0xffa500, + //% block=yellow + Yellow = 0xffff00, + //% block=green + Green = 0x00ff00, + //% block=blue + Blue = 0x0000ff, + //% block=indigo + Indigo = 0x4b0082, + //% block=violet + Violet = 0x8a2be2, + //% block=purple + Purple = 0xff00ff, + //% block=white + White = 0xffffff, + //% block=black + Black = 0x000000, } /** * Different modes for RGB or RGB+W NeoPixel strips */ enum NeoPixelMode { - //% block="RGB (GRB format)" - RGB_GRB = 1, - //% block="RGB+W" - RGBW = 2, - //% block="RGB (RGB format)" - RGB_RGB = 3, + //% block="RGB (GRB format)" + RGB_GRB = 2, + //% block="RGB+W" + RGBW = 3, + //% block="RGB (RGB format)" + RGB_RGB = 4, } /** @@ -41,577 +41,577 @@ enum NeoPixelMode { */ //% weight=5 color=#2699BF icon="\uf110" namespace neopixel { + /** + * A NeoPixel strip + */ + export class Strip { + buf: Buffer; + pin: DigitalPin; + // TODO: encode as bytes instead of 32bit + brightness: number; + start: number; // start offset in LED strip + _length: number; // number of LEDs + _mode: NeoPixelMode; + _matrixWidth: number; // number of leds in a matrix - if any + /** - * A NeoPixel strip + * Shows all LEDs to a given color (range 0-255 for r, g, b). + * @param rgb RGB color of the LED */ - export class Strip { - buf: Buffer; - pin: DigitalPin; - // TODO: encode as bytes instead of 32bit - brightness: number; - start: number; // start offset in LED strip - _length: number; // number of LEDs - _mode: NeoPixelMode; - _matrixWidth: number; // number of leds in a matrix - if any - - /** - * Shows all LEDs to a given color (range 0-255 for r, g, b). - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" - //% strip.defl=strip - //% weight=85 blockGap=8 - //% parts="neopixel" - //% subcategory=Stripe - showColor(rgb: number) { - rgb = rgb >> 0; - this.setAllRGB(rgb); - this.show(); - } - - /** - * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red - * @param endHue the end hue value for the rainbow - */ - //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" - //% strip.defl=strip - //% startHue.shadow="colorWheelHsvPicker" - //% endHue.shadow="colorWheelHsvPicker" - //% weight=85 blockGap=8 - //% parts="neopixel" - //% subcategory=Stripe - showRainbow(startHue: number = 1, endHue: number = 255) { - if (this._length <= 0) return; - - startHue = (startHue * 360) / 255; - startHue = startHue >> 0; - endHue = (endHue * 360) / 255; - endHue = endHue >> 0; - - const saturation = 100; - const luminance = 50; - const steps = this._length; - const direction = HueInterpolationDirection.Clockwise; - // if (endHue > startHue) { - // direction = HueInterpolationDirection.Clockwise; - // } else if (endHue < startHue) { - // direction = HueInterpolationDirection.CounterClockwise; - // } - - //hue - const h1 = startHue; - const h2 = endHue; - let hDistCW; - let hDistCCW; - let hStepCW; - let hStepCCW; - - // In case we have a full rainbow - if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { - hDistCW = 360; - hDistCCW = 360; - } else { - hDistCW = (h2 + 360 - h1) % 360; - hDistCCW = (h1 + 360 - h2) % 360; - } - hStepCW = Math.idiv(hDistCW * 100, steps); - hStepCCW = Math.idiv(-(hDistCCW * 100), steps); - let hStep: number; - - if (direction === HueInterpolationDirection.Clockwise) { - hStep = hStepCW; - } else if (direction === HueInterpolationDirection.CounterClockwise) { - hStep = hStepCCW; - } else { - hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; - } - - const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation - - //sat - const s1 = saturation; - const s2 = saturation; - const sDist = s2 - s1; - const sStep = Math.idiv(sDist, steps); - const s1_100 = s1 * 100; - - //lum - const l1 = luminance; - const l2 = luminance; - const lDist = l2 - l1; - const lStep = Math.idiv(lDist, steps); - const l1_100 = l1 * 100; - - //interpolate - if (steps === 1) { - this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); - } else { - this.setPixelColor(0, hsl(startHue, saturation, luminance)); - for (let i = 1; i < steps - 1; i++) { - const h = Math.idiv(h1_100 + i * hStep, 100) + 360; - const s = Math.idiv(s1_100 + i * sStep, 100); - const l = Math.idiv(l1_100 + i * lStep, 100); - this.setPixelColor(i, hsl(h, s, l)); - } - this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); - } - this.show(); - } - - /** - * Displays a vertical bar graph based on the `value` and `high` value. - * If `high` is 0, the chart gets adjusted automatically. - * @param value current value to plot - * @param high maximum value, eg: 255 - */ - //% weight=84 - //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - //% strip.defl=strip - //% icon="\uf080" - //% parts="neopixel" - //% subcategory=Stripe - showBarGraph(value: number, high: number): void { - if (high <= 0) { - this.clear(); - this.setPixelColor(0, NeoPixelColors.Yellow); - this.show(); - return; - } - - value = Math.abs(value); - const n = this._length; - const n1 = n - 1; - let v = Math.idiv(value * n, high); - if (v == 0) { - this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); - } else { - for (let i = 0; i < n; ++i) { - if (i <= v) { - const b = Math.idiv(i * 255, n1); - this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } else this.setPixelColor(i, 0); - } - } - this.show(); - } - - /** - * Set LED to a given color (range 0-255 for r, g, b). - * You need to call ``show`` to make the changes visible. - * @param pixeloffset position of the NeoPixel in the strip - * @param range how many pixels starting at position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" - //% strip.defl=strip - //% number.defl=1 - //% number.min=1 - //% number.min=255 - //% blockGap=8 - //% weight=80 - //% parts="neopixel" - //% subcategory=Stripe - setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { - for (let i = 0; i < number; i++) { - this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); - } - } - - setPixelColor(pixeloffset: number, rgb: number): void { - this.setPixelRGB(pixeloffset >> 0, rgb >> 0); - } - - /** - * Sets the number of pixels in a matrix shaped strip - * @param width number of pixels in a row - */ - //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" - //% strip.defl=strip - //% blockGap=8 - //% weight=5 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixWidth(width: number) { - this._matrixWidth = Math.min(this._length, width >> 0); - } - - /** - * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip - * You need to call ``show`` to make the changes visible. - * @param x horizontal position - * @param y horizontal position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" - //% strip.defl=strip - //% weight=4 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixColor(x: number, y: number, rgb: number) { - if (this._matrixWidth <= 0) return; // not a matrix, ignore - x = x >> 0; - y = y >> 0; - rgb = rgb >> 0; - const cols = Math.idiv(this._length, this._matrixWidth); - if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; - let i = x + y * this._matrixWidth; - this.setPixelColor(i, rgb); - } - - /** - * Send all the changes to the strip. - */ - //% blockId="neopixel_show" block="%strip|show" blockGap=8 - //% strip.defl=strip - //% weight=79 - //% parts="neopixel" - //% subcategory=Stripe - show() { - // only supported in beta - // ws2812b.setBufferMode(this.pin, this._mode); - ws2812b.sendBuffer(this.buf, this.pin); - console.log("Estimated current for neopixels = " + this.power()); - } - - /** - * Turn off all LEDs. - * You need to call ``show`` to make the changes visible. - */ - //% blockId="neopixel_clear" block="%strip|clear" - //% strip.defl=strip - //% weight=76 - //% parts="neopixel" - //% subcategory=Stripe - clear(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.fill(0, this.start * stride, this._length * stride); - } - - /** - * Gets the number of pixels declared on the strip - */ - //% blockId="neopixel_length" block="%strip|length" blockGap=8 - //% strip.defl=strip - //% weight=60 - //% subcategory=Stripe - length() { - return this._length; - } - - /** - * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ - //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 - //% brightness.defl=255 brightness.min=0 brightness.max=255 - //% strip.defl=strip - //% weight=59 - //% parts="neopixel" - //% subcategory=Stripe - setBrightness(brightness: number): void { - this.brightness = brightness & 0xff; - } + //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=85 blockGap=8 + //% parts="neopixel" + //% subcategory=Stripe + showColor(rgb: number) { + rgb = rgb >> 0; + this.setAllRGB(rgb); + this.show(); + } - /** - * Apply brightness to current colors using a quadratic easing function. - **/ - //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 - //% strip.defl=strip - //% weight=58 - //% parts="neopixel" - //% subcategory=Stripe - // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? - easeBrightness(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const buf = this.buf; - const end = this.start + this._length; - const mid = Math.idiv(this._length, 2); - for (let i = this.start; i < end; ++i) { - const k = i - this.start; - const ledoffset = i * stride; - const br = - k > mid - ? Math.idiv( - 255 * (this._length - 1 - k) * (this._length - 1 - k), - mid * mid - ) - : Math.idiv(255 * k * k, mid * mid); - const r = (buf[ledoffset + 0] * br) >> 8; - buf[ledoffset + 0] = r; - const g = (buf[ledoffset + 1] * br) >> 8; - buf[ledoffset + 1] = g; - const b = (buf[ledoffset + 2] * br) >> 8; - buf[ledoffset + 2] = b; - if (stride == 4) { - const w = (buf[ledoffset + 3] * br) >> 8; - buf[ledoffset + 3] = w; - } - } + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red + * @param endHue the end hue value for the rainbow + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% strip.defl=strip + //% startHue.shadow="colorWheelHsvPicker" + //% endHue.shadow="colorWheelHsvPicker" + //% weight=85 blockGap=8 + //% parts="neopixel" + //% subcategory=Stripe + showRainbow(startHue: number = 1, endHue: number = 255) { + if (this._length <= 0) return; + + startHue = (startHue * 360) / 255; + startHue = startHue >> 0; + endHue = (endHue * 360) / 255; + endHue = endHue >> 0; + + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + // if (endHue > startHue) { + // direction = HueInterpolationDirection.Clockwise; + // } else if (endHue < startHue) { + // direction = HueInterpolationDirection.CounterClockwise; + // } + + //hue + const h1 = startHue; + const h2 = endHue; + let hDistCW; + let hDistCCW; + let hStepCW; + let hStepCCW; + + // In case we have a full rainbow + if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { + hDistCW = 360; + hDistCCW = 360; + } else { + hDistCW = (h2 + 360 - h1) % 360; + hDistCCW = (h1 + 360 - h2) % 360; + } + hStepCW = Math.idiv(hDistCW * 100, steps); + hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100; + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); + this.setPixelColor(i, hsl(h, s, l)); } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); + } + this.show(); + } - /** - * Shift LEDs forward and clear with zeros. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to shift forward, eg: 1 - */ - //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=40 - //% parts="neopixel" - //% subcategory=Stripe - shift(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.shift( - -offset * stride, - this.start * stride, - this._length * stride - ); + /** + * Displays a vertical bar graph based on the `value` and `high` value. + * If `high` is 0, the chart gets adjusted automatically. + * @param value current value to plot + * @param high maximum value, eg: 255 + */ + //% weight=84 + //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + //% strip.defl=strip + //% icon="\uf080" + //% parts="neopixel" + //% subcategory=Stripe + showBarGraph(value: number, high: number): void { + if (high <= 0) { + this.clear(); + this.setPixelColor(0, NeoPixelColors.Yellow); + this.show(); + return; + } + + value = Math.abs(value); + const n = this._length; + const n1 = n - 1; + let v = Math.idiv(value * n, high); + if (v == 0) { + this.setPixelColor(0, 0x666600); + for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); + } else { + for (let i = 0; i < n; ++i) { + if (i <= v) { + const b = Math.idiv(i * 255, n1); + this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); + } else this.setPixelColor(i, 0); } + } + this.show(); + } - /** - * Rotate LEDs forward. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to rotate forward, eg: 1 - */ - //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=39 - //% parts="neopixel" - //% subcategory=Stripe - rotate(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.rotate( - -offset * stride, - this.start * stride, - this._length * stride - ); - } + /** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" + //% strip.defl=strip + //% number.defl=1 + //% number.min=1 + //% number.min=255 + //% blockGap=8 + //% weight=80 + //% parts="neopixel" + //% subcategory=Stripe + setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + for (let i = 0; i < number; i++) { + this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + } + } - /** - * Set the pin where the neopixel is connected, defaults to P0. - */ - //% weight=10 - //% parts="neopixel" - //% subcategory=Stripe - setPin(pin: DigitalPin): void { - this.pin = pin; - pins.digitalWritePin(this.pin, 0); - // don't yield to avoid races on initialization - } + setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); + } - /** - * Estimates the electrical current (mA) consumed by the current light configuration. - */ - //% weight=9 blockId=neopixel_power block="%strip|power (mA)" - //% strip.defl=strip - //% subcategory=Stripe - power(): number { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const end = this.start + this._length; - let p = 0; - for (let i = this.start; i < end; ++i) { - for (let j = 0; j < stride; ++j) { - p += this.buf[i + j]; - } - } - return ( - Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + - Math.idiv(p * 480, 10000) - ); /* rought approximation */ - } + /** + * Sets the number of pixels in a matrix shaped strip + * @param width number of pixels in a row + */ + //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" + //% strip.defl=strip + //% blockGap=8 + //% weight=5 + //% parts="neopixel" + //% subcategory=Matrix + setMatrixWidth(width: number) { + this._matrixWidth = Math.min(this._length, width >> 0); + } - private setBufferRGB( - offset: number, - red: number, - green: number, - blue: number - ): void { - if (this._mode === NeoPixelMode.RGB_RGB) { - this.buf[offset + 0] = red; - this.buf[offset + 1] = green; - } else { - this.buf[offset + 0] = green; - this.buf[offset + 1] = red; - } - this.buf[offset + 2] = blue; - } + /** + * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip + * You need to call ``show`` to make the changes visible. + * @param x horizontal position + * @param y horizontal position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=4 + //% parts="neopixel" + //% subcategory=Matrix + setMatrixColor(x: number, y: number, rgb: number) { + if (this._matrixWidth <= 0) return; // not a matrix, ignore + x = x >> 0; + y = y >> 0; + rgb = rgb >> 0; + const cols = Math.idiv(this._length, this._matrixWidth); + if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; + let i = x + y * this._matrixWidth; + this.setPixelColor(i, rgb); + } - private setAllRGB(rgb: number) { - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - const br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - const end = this.start + this._length; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - for (let i = this.start; i < end; ++i) { - this.setBufferRGB(i * stride, red, green, blue); - } - } - private setPixelRGB(pixeloffset: number, rgb: number): void { - if (pixeloffset < 0 || pixeloffset >= this._length) return; - - let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - pixeloffset = (pixeloffset + this.start) * stride; - - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - let br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - this.setBufferRGB(pixeloffset, red, green, blue); - } + /** + * Send all the changes to the strip. + */ + //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% strip.defl=strip + //% weight=79 + //% parts="neopixel" + //% subcategory=Stripe + show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); + console.log("Estimated current for neopixels = " + this.power()); + } - private setPixelW(pixeloffset: number, white: number): void { - if (this._mode !== NeoPixelMode.RGBW) return; + /** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ + //% blockId="neopixel_clear" block="%strip|clear" + //% strip.defl=strip + //% weight=76 + //% parts="neopixel" + //% subcategory=Stripe + clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); + } - if (pixeloffset < 0 || pixeloffset >= this._length) return; + /** + * Gets the number of pixels declared on the strip + */ + //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% strip.defl=strip + //% weight=60 + //% subcategory=Stripe + length() { + return this._length; + } - pixeloffset = (pixeloffset + this.start) * 4; + /** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% strip.defl=strip + //% weight=59 + //% parts="neopixel" + //% subcategory=Stripe + setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; + } - let br = this.brightness; - if (br < 255) { - white = (white * br) >> 8; - } - let buf = this.buf; - buf[pixeloffset + 3] = white; + /** + * Apply brightness to current colors using a quadratic easing function. + **/ + //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% strip.defl=strip + //% weight=58 + //% parts="neopixel" + //% subcategory=Stripe + // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? + easeBrightness(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const buf = this.buf; + const end = this.start + this._length; + const mid = Math.idiv(this._length, 2); + for (let i = this.start; i < end; ++i) { + const k = i - this.start; + const ledoffset = i * stride; + const br = + k > mid + ? Math.idiv( + 255 * (this._length - 1 - k) * (this._length - 1 - k), + mid * mid + ) + : Math.idiv(255 * k * k, mid * mid); + const r = (buf[ledoffset + 0] * br) >> 8; + buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; + buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; + buf[ledoffset + 2] = b; + if (stride == 4) { + const w = (buf[ledoffset + 3] * br) >> 8; + buf[ledoffset + 3] = w; } + } } /** - * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected. - * @param numleds number of leds in the strip, eg: 24,30,60,64 + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" - //% weight=90 blockGap=8 + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=40 //% parts="neopixel" //% subcategory=Stripe - //% trackArgs=0,2 - //% blockSetVariable=strip - export function create(pin: DigitalPin, numleds: number): Strip { - let strip = new Strip(); - let mode: NeoPixelMode = NeoPixelMode.RGB_GRB; - let stride = mode === NeoPixelMode.RGBW ? 4 : 3; - strip.buf = pins.createBuffer(numleds * stride); - strip.start = 0; - strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB_GRB; - strip._matrixWidth = 0; - strip.setBrightness(128); - strip.setPin(pin); - return strip; + shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); } /** - * Selects a color from color picker - * @param + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 */ - //% weight=85 blockGap=8 - //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" - //% red.defl=255 red.min=0 red.max=255 - //% blue.defl=255 blue.min=0 blue.max=255 - //% green.defl=255 green.min=0 green.max=255 - export function rgb(red: number, green: number, blue: number): number { - return packRGB(red, green, blue); + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=39 + //% parts="neopixel" + //% subcategory=Stripe + rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); } /** - * Gets the RGB value of a known color + * Set the pin where the neopixel is connected, defaults to P0. */ - //% weight=85 blockGap=8 - //% blockId="neopixel_colors" block="%color" - export function colors(color: NeoPixelColors): number { - return color; + //% weight=10 + //% parts="neopixel" + //% subcategory=Stripe + setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization } - function packRGB(a: number, b: number, c: number): number { - return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); + /** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ + //% weight=9 blockId=neopixel_power block="%strip|power (mA)" + //% strip.defl=strip + //% subcategory=Stripe + power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; + } + } + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ } - function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xff; - return r; + + private setBufferRGB( + offset: number, + red: number, + green: number, + blue: number + ): void { + if (this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; + } else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; + } + this.buf[offset + 2] = blue; } - function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xff; - return g; + + private setAllRGB(rgb: number) { + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + const br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue); + } } - function unpackB(rgb: number): number { - let b = rgb & 0xff; - return b; + private setPixelRGB(pixeloffset: number, rgb: number): void { + if (pixeloffset < 0 || pixeloffset >= this._length) return; + + let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + pixeloffset = (pixeloffset + this.start) * stride; + + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + let br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + this.setBufferRGB(pixeloffset, red, green, blue); } - /** - * Converts a hue saturation luminosity value into a RGB color - * @param h hue from 0 to 360 - * @param s saturation from 0 to 99 - * @param l luminosity from 0 to 99 - */ - export function hsl(h: number, s: number, l: number): number { - h = Math.round(h); - s = Math.round(s); - l = Math.round(l); - - h = h % 360; - s = Math.clamp(0, 99, s); - l = Math.clamp(0, 99, l); - let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] - let h1 = Math.idiv(h, 60); //[0,6] - let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] - let temp = Math.abs((h1 % 2 << 8) + h2 - 256); - let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color - let r$: number; - let g$: number; - let b$: number; - if (h1 == 0) { - r$ = c; - g$ = x; - b$ = 0; - } else if (h1 == 1) { - r$ = x; - g$ = c; - b$ = 0; - } else if (h1 == 2) { - r$ = 0; - g$ = c; - b$ = x; - } else if (h1 == 3) { - r$ = 0; - g$ = x; - b$ = c; - } else if (h1 == 4) { - r$ = x; - g$ = 0; - b$ = c; - } else if (h1 == 5) { - r$ = c; - g$ = 0; - b$ = x; - } - let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); - let r = r$ + m; - let g = g$ + m; - let b = b$ + m; - return packRGB(r, g, b); - } + private setPixelW(pixeloffset: number, white: number): void { + if (this._mode !== NeoPixelMode.RGBW) return; - export enum HueInterpolationDirection { - Clockwise, - CounterClockwise, - Shortest, + if (pixeloffset < 0 || pixeloffset >= this._length) return; + + pixeloffset = (pixeloffset + this.start) * 4; + + let br = this.brightness; + if (br < 255) { + white = (white * br) >> 8; + } + let buf = this.buf; + buf[pixeloffset + 3] = white; + } + } + + /** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected. + * @param numleds number of leds in the strip, eg: 24,30,60,64 + */ + //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" + //% weight=90 blockGap=8 + //% parts="neopixel" + //% subcategory=Stripe + //% trackArgs=0,2 + //% blockSetVariable=strip + export function create(pin: DigitalPin, numleds: number): Strip { + let strip = new Strip(); + let mode: NeoPixelMode = NeoPixelMode.RGB_GRB; + let stride = mode === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB_GRB; + strip._matrixWidth = 0; + strip.setBrightness(128); + strip.setPin(pin); + return strip; + } + + /** + * Selects a color from color picker + * @param + */ + //% weight=85 blockGap=8 + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% red.defl=255 red.min=0 red.max=255 + //% blue.defl=255 blue.min=0 blue.max=255 + //% green.defl=255 green.min=0 green.max=255 + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); + } + + /** + * Gets the RGB value of a known color + */ + //% weight=85 blockGap=8 + //% blockId="neopixel_colors" block="%color" + export function colors(color: NeoPixelColors): number { + return color; + } + + function packRGB(a: number, b: number, c: number): number { + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); + } + function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xff; + return r; + } + function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xff; + return g; + } + function unpackB(rgb: number): number { + let b = rgb & 0xff; + return b; + } + + /** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ + export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; + g$ = x; + b$ = 0; + } else if (h1 == 1) { + r$ = x; + g$ = c; + b$ = 0; + } else if (h1 == 2) { + r$ = 0; + g$ = c; + b$ = x; + } else if (h1 == 3) { + r$ = 0; + g$ = x; + b$ = c; + } else if (h1 == 4) { + r$ = x; + g$ = 0; + b$ = c; + } else if (h1 == 5) { + r$ = c; + g$ = 0; + b$ = x; } + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); + } + + export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest, + } } From 8de10b039ec8914aab6791e0373f0b08826de816 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 13:50:58 +0100 Subject: [PATCH 112/253] enum comparision with valueOf() --- neopixel.ts | 1120 +++++++++++++++++++++++++-------------------------- 1 file changed, 560 insertions(+), 560 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index c4d2b57..fb0ea10 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -2,38 +2,38 @@ * Well known colors for a NeoPixel strip */ enum NeoPixelColors { - //% block=red - Red = 0xff0000, - //% block=orange - Orange = 0xffa500, - //% block=yellow - Yellow = 0xffff00, - //% block=green - Green = 0x00ff00, - //% block=blue - Blue = 0x0000ff, - //% block=indigo - Indigo = 0x4b0082, - //% block=violet - Violet = 0x8a2be2, - //% block=purple - Purple = 0xff00ff, - //% block=white - White = 0xffffff, - //% block=black - Black = 0x000000, + //% block=red + Red = 0xff0000, + //% block=orange + Orange = 0xffa500, + //% block=yellow + Yellow = 0xffff00, + //% block=green + Green = 0x00ff00, + //% block=blue + Blue = 0x0000ff, + //% block=indigo + Indigo = 0x4b0082, + //% block=violet + Violet = 0x8a2be2, + //% block=purple + Purple = 0xff00ff, + //% block=white + White = 0xffffff, + //% block=black + Black = 0x000000, } /** * Different modes for RGB or RGB+W NeoPixel strips */ enum NeoPixelMode { - //% block="RGB (GRB format)" - RGB_GRB = 2, - //% block="RGB+W" - RGBW = 3, - //% block="RGB (RGB format)" - RGB_RGB = 4, + //% block="RGB (GRB format)" + RGB_GRB = 1, + //% block="RGB+W" + RGBW = 2, + //% block="RGB (RGB format)" + RGB_RGB = 3, } /** @@ -41,577 +41,577 @@ enum NeoPixelMode { */ //% weight=5 color=#2699BF icon="\uf110" namespace neopixel { - /** - * A NeoPixel strip - */ - export class Strip { - buf: Buffer; - pin: DigitalPin; - // TODO: encode as bytes instead of 32bit - brightness: number; - start: number; // start offset in LED strip - _length: number; // number of LEDs - _mode: NeoPixelMode; - _matrixWidth: number; // number of leds in a matrix - if any - /** - * Shows all LEDs to a given color (range 0-255 for r, g, b). - * @param rgb RGB color of the LED + * A NeoPixel strip */ - //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" - //% strip.defl=strip - //% weight=85 blockGap=8 - //% parts="neopixel" - //% subcategory=Stripe - showColor(rgb: number) { - rgb = rgb >> 0; - this.setAllRGB(rgb); - this.show(); - } + export class Strip { + buf: Buffer; + pin: DigitalPin; + // TODO: encode as bytes instead of 32bit + brightness: number; + start: number; // start offset in LED strip + _length: number; // number of LEDs + _mode: NeoPixelMode; + _matrixWidth: number; // number of leds in a matrix - if any + + /** + * Shows all LEDs to a given color (range 0-255 for r, g, b). + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=85 blockGap=8 + //% parts="neopixel" + //% subcategory=Stripe + showColor(rgb: number) { + rgb = rgb >> 0; + this.setAllRGB(rgb); + this.show(); + } - /** - * Shows a rainbow pattern on all LEDs. - * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red - * @param endHue the end hue value for the rainbow - */ - //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" - //% strip.defl=strip - //% startHue.shadow="colorWheelHsvPicker" - //% endHue.shadow="colorWheelHsvPicker" - //% weight=85 blockGap=8 - //% parts="neopixel" - //% subcategory=Stripe - showRainbow(startHue: number = 1, endHue: number = 255) { - if (this._length <= 0) return; - - startHue = (startHue * 360) / 255; - startHue = startHue >> 0; - endHue = (endHue * 360) / 255; - endHue = endHue >> 0; - - const saturation = 100; - const luminance = 50; - const steps = this._length; - const direction = HueInterpolationDirection.Clockwise; - // if (endHue > startHue) { - // direction = HueInterpolationDirection.Clockwise; - // } else if (endHue < startHue) { - // direction = HueInterpolationDirection.CounterClockwise; - // } - - //hue - const h1 = startHue; - const h2 = endHue; - let hDistCW; - let hDistCCW; - let hStepCW; - let hStepCCW; - - // In case we have a full rainbow - if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { - hDistCW = 360; - hDistCCW = 360; - } else { - hDistCW = (h2 + 360 - h1) % 360; - hDistCCW = (h1 + 360 - h2) % 360; - } - hStepCW = Math.idiv(hDistCW * 100, steps); - hStepCCW = Math.idiv(-(hDistCCW * 100), steps); - let hStep: number; - - if (direction === HueInterpolationDirection.Clockwise) { - hStep = hStepCW; - } else if (direction === HueInterpolationDirection.CounterClockwise) { - hStep = hStepCCW; - } else { - hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; - } - - const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation - - //sat - const s1 = saturation; - const s2 = saturation; - const sDist = s2 - s1; - const sStep = Math.idiv(sDist, steps); - const s1_100 = s1 * 100; - - //lum - const l1 = luminance; - const l2 = luminance; - const lDist = l2 - l1; - const lStep = Math.idiv(lDist, steps); - const l1_100 = l1 * 100; - - //interpolate - if (steps === 1) { - this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); - } else { - this.setPixelColor(0, hsl(startHue, saturation, luminance)); - for (let i = 1; i < steps - 1; i++) { - const h = Math.idiv(h1_100 + i * hStep, 100) + 360; - const s = Math.idiv(s1_100 + i * sStep, 100); - const l = Math.idiv(l1_100 + i * lStep, 100); - this.setPixelColor(i, hsl(h, s, l)); + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red + * @param endHue the end hue value for the rainbow + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% strip.defl=strip + //% startHue.shadow="colorWheelHsvPicker" + //% endHue.shadow="colorWheelHsvPicker" + //% weight=85 blockGap=8 + //% parts="neopixel" + //% subcategory=Stripe + showRainbow(startHue: number = 1, endHue: number = 255) { + if (this._length <= 0) return; + + startHue = (startHue * 360) / 255; + startHue = startHue >> 0; + endHue = (endHue * 360) / 255; + endHue = endHue >> 0; + + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + // if (endHue > startHue) { + // direction = HueInterpolationDirection.Clockwise; + // } else if (endHue < startHue) { + // direction = HueInterpolationDirection.CounterClockwise; + // } + + //hue + const h1 = startHue; + const h2 = endHue; + let hDistCW; + let hDistCCW; + let hStepCW; + let hStepCCW; + + // In case we have a full rainbow + if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { + hDistCW = 360; + hDistCCW = 360; + } else { + hDistCW = (h2 + 360 - h1) % 360; + hDistCCW = (h1 + 360 - h2) % 360; + } + hStepCW = Math.idiv(hDistCW * 100, steps); + hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100; + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); + this.setPixelColor(i, hsl(h, s, l)); + } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); + } + this.show(); } - this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); - } - this.show(); - } - /** - * Displays a vertical bar graph based on the `value` and `high` value. - * If `high` is 0, the chart gets adjusted automatically. - * @param value current value to plot - * @param high maximum value, eg: 255 - */ - //% weight=84 - //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - //% strip.defl=strip - //% icon="\uf080" - //% parts="neopixel" - //% subcategory=Stripe - showBarGraph(value: number, high: number): void { - if (high <= 0) { - this.clear(); - this.setPixelColor(0, NeoPixelColors.Yellow); - this.show(); - return; - } - - value = Math.abs(value); - const n = this._length; - const n1 = n - 1; - let v = Math.idiv(value * n, high); - if (v == 0) { - this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); - } else { - for (let i = 0; i < n; ++i) { - if (i <= v) { - const b = Math.idiv(i * 255, n1); - this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } else this.setPixelColor(i, 0); + /** + * Displays a vertical bar graph based on the `value` and `high` value. + * If `high` is 0, the chart gets adjusted automatically. + * @param value current value to plot + * @param high maximum value, eg: 255 + */ + //% weight=84 + //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + //% strip.defl=strip + //% icon="\uf080" + //% parts="neopixel" + //% subcategory=Stripe + showBarGraph(value: number, high: number): void { + if (high <= 0) { + this.clear(); + this.setPixelColor(0, NeoPixelColors.Yellow); + this.show(); + return; + } + + value = Math.abs(value); + const n = this._length; + const n1 = n - 1; + let v = Math.idiv(value * n, high); + if (v == 0) { + this.setPixelColor(0, 0x666600); + for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); + } else { + for (let i = 0; i < n; ++i) { + if (i <= v) { + const b = Math.idiv(i * 255, n1); + this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); + } else this.setPixelColor(i, 0); + } + } + this.show(); } - } - this.show(); - } - /** - * Set LED to a given color (range 0-255 for r, g, b). - * You need to call ``show`` to make the changes visible. - * @param pixeloffset position of the NeoPixel in the strip - * @param range how many pixels starting at position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" - //% strip.defl=strip - //% number.defl=1 - //% number.min=1 - //% number.min=255 - //% blockGap=8 - //% weight=80 - //% parts="neopixel" - //% subcategory=Stripe - setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { - for (let i = 0; i < number; i++) { - this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); - } - } + /** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" + //% strip.defl=strip + //% number.defl=1 + //% number.min=1 + //% number.min=255 + //% blockGap=8 + //% weight=80 + //% parts="neopixel" + //% subcategory=Stripe + setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + for (let i = 0; i < number; i++) { + this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + } + } - setPixelColor(pixeloffset: number, rgb: number): void { - this.setPixelRGB(pixeloffset >> 0, rgb >> 0); - } + setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); + } - /** - * Sets the number of pixels in a matrix shaped strip - * @param width number of pixels in a row - */ - //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" - //% strip.defl=strip - //% blockGap=8 - //% weight=5 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixWidth(width: number) { - this._matrixWidth = Math.min(this._length, width >> 0); - } + /** + * Sets the number of pixels in a matrix shaped strip + * @param width number of pixels in a row + */ + //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" + //% strip.defl=strip + //% blockGap=8 + //% weight=5 + //% parts="neopixel" + //% subcategory=Matrix + setMatrixWidth(width: number) { + this._matrixWidth = Math.min(this._length, width >> 0); + } - /** - * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip - * You need to call ``show`` to make the changes visible. - * @param x horizontal position - * @param y horizontal position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" - //% strip.defl=strip - //% weight=4 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixColor(x: number, y: number, rgb: number) { - if (this._matrixWidth <= 0) return; // not a matrix, ignore - x = x >> 0; - y = y >> 0; - rgb = rgb >> 0; - const cols = Math.idiv(this._length, this._matrixWidth); - if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; - let i = x + y * this._matrixWidth; - this.setPixelColor(i, rgb); - } + /** + * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip + * You need to call ``show`` to make the changes visible. + * @param x horizontal position + * @param y horizontal position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" + //% strip.defl=strip + //% weight=4 + //% parts="neopixel" + //% subcategory=Matrix + setMatrixColor(x: number, y: number, rgb: number) { + if (this._matrixWidth <= 0) return; // not a matrix, ignore + x = x >> 0; + y = y >> 0; + rgb = rgb >> 0; + const cols = Math.idiv(this._length, this._matrixWidth); + if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; + let i = x + y * this._matrixWidth; + this.setPixelColor(i, rgb); + } - /** - * Send all the changes to the strip. - */ - //% blockId="neopixel_show" block="%strip|show" blockGap=8 - //% strip.defl=strip - //% weight=79 - //% parts="neopixel" - //% subcategory=Stripe - show() { - // only supported in beta - // ws2812b.setBufferMode(this.pin, this._mode); - ws2812b.sendBuffer(this.buf, this.pin); - console.log("Estimated current for neopixels = " + this.power()); - } + /** + * Send all the changes to the strip. + */ + //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% strip.defl=strip + //% weight=79 + //% parts="neopixel" + //% subcategory=Stripe + show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); + console.log("Estimated current for neopixels = " + this.power()); + } - /** - * Turn off all LEDs. - * You need to call ``show`` to make the changes visible. - */ - //% blockId="neopixel_clear" block="%strip|clear" - //% strip.defl=strip - //% weight=76 - //% parts="neopixel" - //% subcategory=Stripe - clear(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.fill(0, this.start * stride, this._length * stride); - } + /** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ + //% blockId="neopixel_clear" block="%strip|clear" + //% strip.defl=strip + //% weight=76 + //% parts="neopixel" + //% subcategory=Stripe + clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); + } - /** - * Gets the number of pixels declared on the strip - */ - //% blockId="neopixel_length" block="%strip|length" blockGap=8 - //% strip.defl=strip - //% weight=60 - //% subcategory=Stripe - length() { - return this._length; - } + /** + * Gets the number of pixels declared on the strip + */ + //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% strip.defl=strip + //% weight=60 + //% subcategory=Stripe + length() { + return this._length; + } - /** - * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ - //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 - //% brightness.defl=255 brightness.min=0 brightness.max=255 - //% strip.defl=strip - //% weight=59 - //% parts="neopixel" - //% subcategory=Stripe - setBrightness(brightness: number): void { - this.brightness = brightness & 0xff; - } + /** + * Set the brightness of the strip. This flag only applies to future operation. + * @param brightness a measure of LED brightness in 0-255. eg: 255 + */ + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% strip.defl=strip + //% weight=59 + //% parts="neopixel" + //% subcategory=Stripe + setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; + } - /** - * Apply brightness to current colors using a quadratic easing function. - **/ - //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 - //% strip.defl=strip - //% weight=58 - //% parts="neopixel" - //% subcategory=Stripe - // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? - easeBrightness(): void { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const buf = this.buf; - const end = this.start + this._length; - const mid = Math.idiv(this._length, 2); - for (let i = this.start; i < end; ++i) { - const k = i - this.start; - const ledoffset = i * stride; - const br = - k > mid - ? Math.idiv( - 255 * (this._length - 1 - k) * (this._length - 1 - k), - mid * mid - ) - : Math.idiv(255 * k * k, mid * mid); - const r = (buf[ledoffset + 0] * br) >> 8; - buf[ledoffset + 0] = r; - const g = (buf[ledoffset + 1] * br) >> 8; - buf[ledoffset + 1] = g; - const b = (buf[ledoffset + 2] * br) >> 8; - buf[ledoffset + 2] = b; - if (stride == 4) { - const w = (buf[ledoffset + 3] * br) >> 8; - buf[ledoffset + 3] = w; + /** + * Apply brightness to current colors using a quadratic easing function. + **/ + //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% strip.defl=strip + //% weight=58 + //% parts="neopixel" + //% subcategory=Stripe + // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? + easeBrightness(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const buf = this.buf; + const end = this.start + this._length; + const mid = Math.idiv(this._length, 2); + for (let i = this.start; i < end; ++i) { + const k = i - this.start; + const ledoffset = i * stride; + const br = + k > mid + ? Math.idiv( + 255 * (this._length - 1 - k) * (this._length - 1 - k), + mid * mid + ) + : Math.idiv(255 * k * k, mid * mid); + const r = (buf[ledoffset + 0] * br) >> 8; + buf[ledoffset + 0] = r; + const g = (buf[ledoffset + 1] * br) >> 8; + buf[ledoffset + 1] = g; + const b = (buf[ledoffset + 2] * br) >> 8; + buf[ledoffset + 2] = b; + if (stride == 4) { + const w = (buf[ledoffset + 3] * br) >> 8; + buf[ledoffset + 3] = w; + } + } } - } - } - /** - * Shift LEDs forward and clear with zeros. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to shift forward, eg: 1 - */ - //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=40 - //% parts="neopixel" - //% subcategory=Stripe - shift(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.shift( - -offset * stride, - this.start * stride, - this._length * stride - ); + /** + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 + */ + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=40 + //% parts="neopixel" + //% subcategory=Stripe + shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); + } + + /** + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 + */ + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% strip.defl=strip + //% weight=39 + //% parts="neopixel" + //% subcategory=Stripe + rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); + } + + /** + * Set the pin where the neopixel is connected, defaults to P0. + */ + //% weight=10 + //% parts="neopixel" + //% subcategory=Stripe + setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization + } + + /** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ + //% weight=9 blockId=neopixel_power block="%strip|power (mA)" + //% strip.defl=strip + //% subcategory=Stripe + power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; + } + } + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ + } + + private setBufferRGB( + offset: number, + red: number, + green: number, + blue: number + ): void { + if (this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; + } else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; + } + this.buf[offset + 2] = blue; + } + + private setAllRGB(rgb: number) { + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + const br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue); + } + } + private setPixelRGB(pixeloffset: number, rgb: number): void { + if (pixeloffset < 0 || pixeloffset >= this._length) return; + + let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + pixeloffset = (pixeloffset + this.start) * stride; + + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + let br = this.brightness; + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + this.setBufferRGB(pixeloffset, red, green, blue); + } + + private setPixelW(pixeloffset: number, white: number): void { + if (this._mode !== NeoPixelMode.RGBW) return; + + if (pixeloffset < 0 || pixeloffset >= this._length) return; + + pixeloffset = (pixeloffset + this.start) * 4; + + let br = this.brightness; + if (br < 255) { + white = (white * br) >> 8; + } + let buf = this.buf; + buf[pixeloffset + 3] = white; + } } /** - * Rotate LEDs forward. - * You need to call ``show`` to make the changes visible. - * @param offset number of pixels to rotate forward, eg: 1 + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected. + * @param numleds number of leds in the strip, eg: 24,30,60,64 */ - //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 - //% strip.defl=strip - //% weight=39 + //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" + //% weight=90 blockGap=8 //% parts="neopixel" //% subcategory=Stripe - rotate(offset: number = 1): void { - offset = offset >> 0; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - this.buf.rotate( - -offset * stride, - this.start * stride, - this._length * stride - ); + //% trackArgs=0,2 + //% blockSetVariable=strip + export function create(pin: DigitalPin, numleds: number): Strip { + let strip = new Strip(); + const mode = NeoPixelMode.RGB_GRB; + let stride = mode.valueOf() === NeoPixelMode.RGBW.valueOf() ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB_GRB; + strip._matrixWidth = 0; + strip.setBrightness(128); + strip.setPin(pin); + return strip; } /** - * Set the pin where the neopixel is connected, defaults to P0. + * Selects a color from color picker + * @param */ - //% weight=10 - //% parts="neopixel" - //% subcategory=Stripe - setPin(pin: DigitalPin): void { - this.pin = pin; - pins.digitalWritePin(this.pin, 0); - // don't yield to avoid races on initialization + //% weight=85 blockGap=8 + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% red.defl=255 red.min=0 red.max=255 + //% blue.defl=255 blue.min=0 blue.max=255 + //% green.defl=255 green.min=0 green.max=255 + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); } /** - * Estimates the electrical current (mA) consumed by the current light configuration. + * Gets the RGB value of a known color */ - //% weight=9 blockId=neopixel_power block="%strip|power (mA)" - //% strip.defl=strip - //% subcategory=Stripe - power(): number { - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - const end = this.start + this._length; - let p = 0; - for (let i = this.start; i < end; ++i) { - for (let j = 0; j < stride; ++j) { - p += this.buf[i + j]; - } - } - return ( - Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + - Math.idiv(p * 480, 10000) - ); /* rought approximation */ + //% weight=85 blockGap=8 + //% blockId="neopixel_colors" block="%color" + export function colors(color: NeoPixelColors): number { + return color; } - private setBufferRGB( - offset: number, - red: number, - green: number, - blue: number - ): void { - if (this._mode === NeoPixelMode.RGB_RGB) { - this.buf[offset + 0] = red; - this.buf[offset + 1] = green; - } else { - this.buf[offset + 0] = green; - this.buf[offset + 1] = red; - } - this.buf[offset + 2] = blue; + function packRGB(a: number, b: number, c: number): number { + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); } - - private setAllRGB(rgb: number) { - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - const br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - const end = this.start + this._length; - const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - for (let i = this.start; i < end; ++i) { - this.setBufferRGB(i * stride, red, green, blue); - } + function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xff; + return r; } - private setPixelRGB(pixeloffset: number, rgb: number): void { - if (pixeloffset < 0 || pixeloffset >= this._length) return; - - let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; - pixeloffset = (pixeloffset + this.start) * stride; - - let red = unpackR(rgb); - let green = unpackG(rgb); - let blue = unpackB(rgb); - - let br = this.brightness; - if (br < 255) { - red = (red * br) >> 8; - green = (green * br) >> 8; - blue = (blue * br) >> 8; - } - this.setBufferRGB(pixeloffset, red, green, blue); + function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xff; + return g; + } + function unpackB(rgb: number): number { + let b = rgb & 0xff; + return b; } - private setPixelW(pixeloffset: number, white: number): void { - if (this._mode !== NeoPixelMode.RGBW) return; - - if (pixeloffset < 0 || pixeloffset >= this._length) return; - - pixeloffset = (pixeloffset + this.start) * 4; - - let br = this.brightness; - if (br < 255) { - white = (white * br) >> 8; - } - let buf = this.buf; - buf[pixeloffset + 3] = white; + /** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ + export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; + g$ = x; + b$ = 0; + } else if (h1 == 1) { + r$ = x; + g$ = c; + b$ = 0; + } else if (h1 == 2) { + r$ = 0; + g$ = c; + b$ = x; + } else if (h1 == 3) { + r$ = 0; + g$ = x; + b$ = c; + } else if (h1 == 4) { + r$ = x; + g$ = 0; + b$ = c; + } else if (h1 == 5) { + r$ = c; + g$ = 0; + b$ = x; + } + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); } - } - - /** - * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected. - * @param numleds number of leds in the strip, eg: 24,30,60,64 - */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" - //% weight=90 blockGap=8 - //% parts="neopixel" - //% subcategory=Stripe - //% trackArgs=0,2 - //% blockSetVariable=strip - export function create(pin: DigitalPin, numleds: number): Strip { - let strip = new Strip(); - let mode: NeoPixelMode = NeoPixelMode.RGB_GRB; - let stride = mode === NeoPixelMode.RGBW ? 4 : 3; - strip.buf = pins.createBuffer(numleds * stride); - strip.start = 0; - strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB_GRB; - strip._matrixWidth = 0; - strip.setBrightness(128); - strip.setPin(pin); - return strip; - } - - /** - * Selects a color from color picker - * @param - */ - //% weight=85 blockGap=8 - //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" - //% red.defl=255 red.min=0 red.max=255 - //% blue.defl=255 blue.min=0 blue.max=255 - //% green.defl=255 green.min=0 green.max=255 - export function rgb(red: number, green: number, blue: number): number { - return packRGB(red, green, blue); - } - - /** - * Gets the RGB value of a known color - */ - //% weight=85 blockGap=8 - //% blockId="neopixel_colors" block="%color" - export function colors(color: NeoPixelColors): number { - return color; - } - - function packRGB(a: number, b: number, c: number): number { - return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); - } - function unpackR(rgb: number): number { - let r = (rgb >> 16) & 0xff; - return r; - } - function unpackG(rgb: number): number { - let g = (rgb >> 8) & 0xff; - return g; - } - function unpackB(rgb: number): number { - let b = rgb & 0xff; - return b; - } - - /** - * Converts a hue saturation luminosity value into a RGB color - * @param h hue from 0 to 360 - * @param s saturation from 0 to 99 - * @param l luminosity from 0 to 99 - */ - export function hsl(h: number, s: number, l: number): number { - h = Math.round(h); - s = Math.round(s); - l = Math.round(l); - - h = h % 360; - s = Math.clamp(0, 99, s); - l = Math.clamp(0, 99, l); - let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] - let h1 = Math.idiv(h, 60); //[0,6] - let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] - let temp = Math.abs((h1 % 2 << 8) + h2 - 256); - let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color - let r$: number; - let g$: number; - let b$: number; - if (h1 == 0) { - r$ = c; - g$ = x; - b$ = 0; - } else if (h1 == 1) { - r$ = x; - g$ = c; - b$ = 0; - } else if (h1 == 2) { - r$ = 0; - g$ = c; - b$ = x; - } else if (h1 == 3) { - r$ = 0; - g$ = x; - b$ = c; - } else if (h1 == 4) { - r$ = x; - g$ = 0; - b$ = c; - } else if (h1 == 5) { - r$ = c; - g$ = 0; - b$ = x; + + export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest, } - let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); - let r = r$ + m; - let g = g$ + m; - let b = b$ + m; - return packRGB(r, g, b); - } - - export enum HueInterpolationDirection { - Clockwise, - CounterClockwise, - Shortest, - } } From 51f66187bef3bc45fdf79326b096f854089457f6 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 14:12:19 +0100 Subject: [PATCH 113/253] enum comparision with number cast --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index fb0ea10..fdc022c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -506,7 +506,7 @@ namespace neopixel { export function create(pin: DigitalPin, numleds: number): Strip { let strip = new Strip(); const mode = NeoPixelMode.RGB_GRB; - let stride = mode.valueOf() === NeoPixelMode.RGBW.valueOf() ? 4 : 3; + let stride = Number(mode) === Number(NeoPixelMode.RGBW) ? 4 : 3; strip.buf = pins.createBuffer(numleds * stride); strip.start = 0; strip._length = numleds; From 425d01e44c6107c7e9df7cdbb8c3a323be61b1e5 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 14:15:05 +0100 Subject: [PATCH 114/253] enum type cast --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index fdc022c..528116c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -506,7 +506,7 @@ namespace neopixel { export function create(pin: DigitalPin, numleds: number): Strip { let strip = new Strip(); const mode = NeoPixelMode.RGB_GRB; - let stride = Number(mode) === Number(NeoPixelMode.RGBW) ? 4 : 3; + let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; strip.buf = pins.createBuffer(numleds * stride); strip.start = 0; strip._length = numleds; From 4cafc65d673b9953ce9741ac29a12e8934ba4a64 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 14:55:52 +0100 Subject: [PATCH 115/253] limit number of pins on neopixel blocks --- neopixel.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 528116c..145bde8 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -36,6 +36,16 @@ enum NeoPixelMode { RGB_RGB = 3, } +/** + * Available pins on ports (connectors) + */ +enum HiwonderPins { + P1 = DigitalPin.P1, + P2 = DigitalPin.P2, + P13 = DigitalPin.P13, + P14 = DigitalPin.P14, + P16 = DigitalPin.P16, +} /** * Functions to operate NeoPixel strips. */ @@ -494,7 +504,7 @@ namespace neopixel { /** * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected. + * @param pin the pin where the neopixel is connected on the Hiwonder board * @param numleds number of leds in the strip, eg: 24,30,60,64 */ //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" @@ -503,7 +513,7 @@ namespace neopixel { //% subcategory=Stripe //% trackArgs=0,2 //% blockSetVariable=strip - export function create(pin: DigitalPin, numleds: number): Strip { + export function create(pin: HiwonderPins, numleds: number): Strip { let strip = new Strip(); const mode = NeoPixelMode.RGB_GRB; let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; From f782c5ad4912501307e398b1df6ee2da0d76e327 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 15:15:18 +0100 Subject: [PATCH 116/253] pin type cast --- neopixel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 145bde8..35a5817 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -523,7 +523,8 @@ namespace neopixel { strip._mode = mode || NeoPixelMode.RGB_GRB; strip._matrixWidth = 0; strip.setBrightness(128); - strip.setPin(pin); + let p = DigitalPin[HiwonderPins[pin]]; + strip.setPin(p); return strip; } From b5cfa7f28e7299bc13033fb56586d7efae7b2c52 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 15:44:13 +0100 Subject: [PATCH 117/253] ugly switch statement instead of cast --- neopixel.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 35a5817..8810739 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -523,7 +523,26 @@ namespace neopixel { strip._mode = mode || NeoPixelMode.RGB_GRB; strip._matrixWidth = 0; strip.setBrightness(128); - let p = DigitalPin[HiwonderPins[pin]]; + // TODO: How can we solve this more elegant? When trying to cast, + // we can't use string literals here and can't change DigitalPin to non constant enum + let p; + switch (e) { + case HiwonderPins.P1: + p = DigitalPin.P1; + break; + case HiwonderPins.P2: + p = DigitalPin.P2; + break; + case HiwonderPins.P13: + p = DigitalPin.P13; + break; + case HiwonderPins.P14: + p = DigitalPin.P14; + break; + case HiwonderPins.P16: + p = DigitalPin.P16; + break; + } strip.setPin(p); return strip; } From a94017e78666ac3e747ad7475b2e9b22425695e0 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 15:46:44 +0100 Subject: [PATCH 118/253] e -> pin --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 8810739..1c1b8c3 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -526,7 +526,7 @@ namespace neopixel { // TODO: How can we solve this more elegant? When trying to cast, // we can't use string literals here and can't change DigitalPin to non constant enum let p; - switch (e) { + switch (pin) { case HiwonderPins.P1: p = DigitalPin.P1; break; From 691da9b72d0d89307c49b0a3058d9f24cfb31ee4 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 16:05:24 +0100 Subject: [PATCH 119/253] Don't show bargraph --- neopixel.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 1c1b8c3..641c31f 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -169,18 +169,18 @@ namespace neopixel { this.show(); } - /** - * Displays a vertical bar graph based on the `value` and `high` value. - * If `high` is 0, the chart gets adjusted automatically. - * @param value current value to plot - * @param high maximum value, eg: 255 - */ - //% weight=84 - //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - //% strip.defl=strip - //% icon="\uf080" - //% parts="neopixel" - //% subcategory=Stripe + // /** + // * Displays a vertical bar graph based on the `value` and `high` value. + // * If `high` is 0, the chart gets adjusted automatically. + // * @param value current value to plot + // * @param high maximum value, eg: 255 + // */ + // //% weight=84 + // //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" + // //% strip.defl=strip + // //% icon="\uf080" + // //% parts="neopixel" + // //% subcategory=Stripe showBarGraph(value: number, high: number): void { if (high <= 0) { this.clear(); From 15abdf73106c857b9160c91e08bb488c4e38b129 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 16:26:46 +0100 Subject: [PATCH 120/253] implicit hiwonder initialisation --- StartbitV2.ts | 13 ++++--------- _locales/de/neopixel-strings.json | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 4a11b4f..5d12f44 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -150,15 +150,7 @@ namespace Informatiktheater { } } - /** - * Informatiktheater initialization, please execute at boot time - */ - //% weight=100 - //% blockId=startbit_Init - //% block="initialize Informatiktheater" - //% block.loc.de="initialisiere Informatiktheater" - //% jsdoc.loc.de="Informatiktheater Initialisation, bitte beim Start ausführen." - export function startbit_Init() { + function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -169,6 +161,7 @@ namespace Informatiktheater { } }); basic.pause(2000); + console.log("Informatiktheater initialized"); } let handleCmd: string = ""; @@ -1067,4 +1060,6 @@ namespace Informatiktheater { export function createSongList(): SongList { return new SongList(); } + + startbit_Init(); } diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index e9df320..a33aeb6 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -13,7 +13,7 @@ "NeoPixelMode.RGB_RGB|block": "RGB", "NeoPixelMode.RGB_GRB|block": "GRB", "neopixel.Strip.clear|block": "%strip|ausschalten", - "neopixel.Strip.easeBrightness|block": "%strip|abdunkeln", + "neopixel.Strip.easeBrightness|block": "%strip|Anfang und Ende mit Verlauf abdunkeln", "neopixel.Strip.length|block": "%strip|Länge", "neopixel.Strip.rotate|block": "%strip|rotiere NeoPixel um %offset", "neopixel.Strip.setBrightness|block": "%strip|setze Helligkeit %brightness", From b67362f965bee9df76400777a130548a95eaa348 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 16:59:30 +0100 Subject: [PATCH 121/253] implicit hiwonder initialisation done right --- StartbitV2.ts | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 5d12f44..91b0758 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,3 +1,5 @@ +Informatiktheater.startbit_Init(); + /* Informatiktheater package */ @@ -150,7 +152,7 @@ namespace Informatiktheater { } } - function startbit_Init() { + export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -161,7 +163,6 @@ namespace Informatiktheater { } }); basic.pause(2000); - console.log("Informatiktheater initialized"); } let handleCmd: string = ""; @@ -172,17 +173,6 @@ namespace Informatiktheater { let MESSAGE_MAC = 0xff; let MESSAGE_ANGLE = 0x100; - let servo1Angle: number = 0xfff; - let servo2Angle: number = 0xfff; - - let TM1640_CMD1 = 0x40; - let TM1640_CMD2 = 0xc0; - let TM1640_CMD3 = 0x80; - let _SEGMENTS = [ - 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, - 0x39, 0x5e, 0x79, 0x71, - ]; - function getHandleCmd() { let charStr: string = serial.readString(); handleCmd = handleCmd.concat(charStr); @@ -194,7 +184,6 @@ namespace Informatiktheater { if (cmd.charAt(0).compare("A") == 0) { if (cmd.length == 7) { let arg1Int: number = strToNumber(cmd.substr(1, 2)); - let arg2Int: number = strToNumber(cmd.substr(3, 2)); let arg3Int: number = strToNumber(cmd.substr(5, 2)); if (arg3Int != -1) { @@ -227,12 +216,8 @@ namespace Informatiktheater { } if (arg2Int > 1000) arg2Int = 1000; if (arg1Int == 1) { - servo1Angle = mapValue(arg2Int, 0, 1000, 0, 240); - servo1Angle -= 120; control.raiseEvent(MESSAGE_ANGLE, 1); } else if (arg1Int == 2) { - servo2Angle = mapValue(arg2Int, 0, 1000, 0, 240); - servo2Angle -= 120; control.raiseEvent(MESSAGE_ANGLE, 2); } } @@ -1060,6 +1045,4 @@ namespace Informatiktheater { export function createSongList(): SongList { return new SongList(); } - - startbit_Init(); } From 3386e31efb0532478905b96c5bf4fcc7cdf52d94 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 17:09:06 +0100 Subject: [PATCH 122/253] undo auto init --- StartbitV2.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 91b0758..c2022ae 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,5 +1,3 @@ -Informatiktheater.startbit_Init(); - /* Informatiktheater package */ @@ -152,6 +150,14 @@ namespace Informatiktheater { } } + /** + * Informatiktheater initialization, please execute at boot time + */ + //% weight=100 + //% blockId=startbit_Init + //% block="initialize Informatiktheater" + //% block.loc.de="initialisiere Informatiktheater" + //% jsdoc.loc.de="Informatiktheater Initialisation, bitte beim Start ausführen." export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); From 1921d2fed5b2bc1ed6c7c688a5795e997638e4d3 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 17:23:25 +0100 Subject: [PATCH 123/253] use same sendbufferasm() --- StartbitRGBLight.ts | 9 +++++---- pxt.json | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index c3289ab..bdeb320 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -60,9 +60,9 @@ enum StartbitRGBPixelMode { * QbitRGBLight Functions */ namespace StartbitRGBLight { - //% shim=sendBufferAsmLocale - //% parts="QbitRGBLight" - function sendBuffer(buf: Buffer, pin: DigitalPin) { } + // //% shim=sendBufferAsm + // //% parts="QbitRGBLight" + // function sendBuffer(buf: Buffer, pin: DigitalPin) { } /** * A LHQbitRGBLight class @@ -182,7 +182,8 @@ namespace StartbitRGBLight { } show() { - sendBuffer(this.buf, this.pin); + // sendBuffer(this.buf, this.pin); + ws2812b.sendBuffer(this.buf, this.pin); } clear(): void { diff --git a/pxt.json b/pxt.json index 86dc6c1..758ad3a 100644 --- a/pxt.json +++ b/pxt.json @@ -11,7 +11,6 @@ "README.md", "StartbitV2.ts", "StartbitRGBLight.ts", - "sendbuffer.asm", "neopixel.ts", "_locales/de/neopixel-strings.json", "_locales/de/neopixel-jsdoc-strings.json" From 3d39f20367116fd8d2907607941ea2d8d4afd802 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 17:29:48 +0100 Subject: [PATCH 124/253] remove old sendbuffer stuff --- StartbitRGBLight.ts | 5 ---- sendbuffer.asm | 67 --------------------------------------------- 2 files changed, 72 deletions(-) delete mode 100644 sendbuffer.asm diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index bdeb320..ddb21e2 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -60,10 +60,6 @@ enum StartbitRGBPixelMode { * QbitRGBLight Functions */ namespace StartbitRGBLight { - // //% shim=sendBufferAsm - // //% parts="QbitRGBLight" - // function sendBuffer(buf: Buffer, pin: DigitalPin) { } - /** * A LHQbitRGBLight class */ @@ -182,7 +178,6 @@ namespace StartbitRGBLight { } show() { - // sendBuffer(this.buf, this.pin); ws2812b.sendBuffer(this.buf, this.pin); } diff --git a/sendbuffer.asm b/sendbuffer.asm deleted file mode 100644 index f24cfb5..0000000 --- a/sendbuffer.asm +++ /dev/null @@ -1,67 +0,0 @@ -sendBufferAsmLocale: - - push {r4,r5,r6,r7,lr} - - mov r4, r0 ; save buff - mov r6, r1 ; save pin - - mov r0, r4 - bl BufferMethods::length - mov r5, r0 - - mov r0, r4 - bl BufferMethods::getBytes - mov r4, r0 - - ; setup pin as digital - mov r0, r6 - movs r1, #0 - bl pins::digitalWritePin - - ; load pin address - mov r0, r6 - bl pins::getPinAddress - - ldr r0, [r0, #8] ; get mbed DigitalOut from MicroBitPin - ldr r1, [r0, #4] ; r1-mask for this pin - ldr r2, [r0, #16] ; r2-clraddr - ldr r3, [r0, #12] ; r3-setaddr - - cpsid i ; disable irq - - b .start - -.nextbit: ; C0 - str r1, [r3, #0] ; pin := hi C2 - tst r6, r0 ; C3 - bne .islate ; C4 - str r1, [r2, #0] ; pin := lo C6 -.islate: - lsrs r6, r6, #1 ; r6 >>= 1 C7 - bne .justbit ; C8 - - ; not just a bit - need new byte - adds r4, #1 ; r4++ C9 - subs r5, #1 ; r5-- C10 - bcc .stop ; if (r5<0) goto .stop C11 -.start: - movs r6, #0x80 ; reset mask C12 - nop ; C13 - -.common: ; C13 - str r1, [r2, #0] ; pin := lo C15 - ; always re-load byte - it just fits with the cycles better this way - ldrb r0, [r4, #0] ; r0 := *r4 C17 - b .nextbit ; C20 - -.justbit: ; C10 - ; no nops, branch taken is already 3 cycles - b .common ; C13 - -.stop: - str r1, [r2, #0] ; pin := lo - cpsie i ; enable irq - - pop {r4,r5,r6,r7,pc} - - From 09861eb9356f821c94a38b8d18335a8f99fc1bda Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 17:40:58 +0100 Subject: [PATCH 125/253] Auto init (again) --- StartbitV2.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c2022ae..bcf7de2 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,3 +1,4 @@ +Informatiktheater.startbit_Init(); /* Informatiktheater package */ @@ -150,14 +151,6 @@ namespace Informatiktheater { } } - /** - * Informatiktheater initialization, please execute at boot time - */ - //% weight=100 - //% blockId=startbit_Init - //% block="initialize Informatiktheater" - //% block.loc.de="initialisiere Informatiktheater" - //% jsdoc.loc.de="Informatiktheater Initialisation, bitte beim Start ausführen." export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -169,6 +162,7 @@ namespace Informatiktheater { } }); basic.pause(2000); + console.log("Informatiktheater initialized"); } let handleCmd: string = ""; From bed64bb3eac85896df924194b73096ecc22ec1be Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 18:32:15 +0100 Subject: [PATCH 126/253] added hsv picker --- StartbitV2.ts | 7 ++++++- _locales/de/neopixel-jsdoc-strings.json | 1 + _locales/de/neopixel-strings.json | 1 + neopixel.ts | 25 +++++++++++++++++++++++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bcf7de2..ba70b96 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,4 +1,6 @@ +// Auto init hiwonder board when extension is added Informatiktheater.startbit_Init(); + /* Informatiktheater package */ @@ -58,8 +60,9 @@ namespace Informatiktheater { let trigPin: DigitalPin; //% weight=91 //% blockId=ultrasonic_init - //% block="initialize ultrasonic |%port" + //% block="initialize ultrasonic |%pin" //% block.loc.de="initialisiere Ultraschall|%port" + //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { case startbit_ultrasonicPort.port1: @@ -83,6 +86,8 @@ namespace Informatiktheater { //% blockId=lineFollowSensor_init //% block="initialize line follower sensor|%port" //% block.loc.de="initialisiere Linienfolger-Sensor|%port" + //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) + // Only P1 and P2 are analog inputs export function lineFollowSensor_init(port: startbit_lineFollowPort) { switch (port) { case startbit_lineFollowPort.port1: diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json index f50a889..234cb95 100644 --- a/_locales/de/neopixel-jsdoc-strings.json +++ b/_locales/de/neopixel-jsdoc-strings.json @@ -12,5 +12,6 @@ "neopixel.Strip.showRainbow": "Zeigt ein Regenbogenmuster auf allen NeoPixeln an.", "neopixel.Strip.show": "Sendet alle Änderungen an die NeoPixel.", "neopixel.rgb": "Erstellt eine RGB-Farbe", + "neopixel.hsv_picker": "Erstellt eine Farbe", "neopixel.colors": "bekannte RGB-Farben" } diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index a33aeb6..41315dc 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -27,6 +27,7 @@ "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds Pixeln", "neopixel.Strip.power|block": "%strip|Stromverbrauch (mA)", "neopixel.rgb|block": "rot %red|grün %green|blau %blue", + "neopixel.hsv_picker|block": "Farbe %hue", "neopixel.Strip.setMatrixColor|block": "%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors", "neopixel.Strip.setMatrixWidth|block": "%strip|setze Matrix Breite %width", "{id:category}Neopixel": "NeoPixel" diff --git a/neopixel.ts b/neopixel.ts index 641c31f..d981712 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -548,8 +548,10 @@ namespace neopixel { } /** - * Selects a color from color picker - * @param + * creates a color from rgb numbers + * @param r red channel + * @param g green channel + * @param b blue channel */ //% weight=85 blockGap=8 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" @@ -560,6 +562,18 @@ namespace neopixel { return packRGB(red, green, blue); } + /** + * creates a color from hsv color picker + * @param hue color + */ + //% weight=85 blockGap=8 + //% blockId="neopixel_hsv" block="hue %hue" + //% hue.shadow="colorWheelHsvPicker" + export function hsv_picker(hue: number): number { + let mapped_hue = (hue * 360) / 255; + return hsl(mapped_hue, 100, 50); + } + /** * Gets the RGB value of a known color */ @@ -644,4 +658,11 @@ namespace neopixel { CounterClockwise, Shortest, } + + export function hsl(h: any, mapped_hue: number, s: any): number { + throw new Error("Function not implemented."); + } +} +function hsl(h: any, mapped_hue: number, s: any): number { + throw new Error("Function not implemented."); } From 57c503b062eb8bcec7cc7f089eaaae1e67fb8116 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 15 Mar 2023 18:37:25 +0100 Subject: [PATCH 127/253] removed accidental added func prototypes --- neopixel.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index d981712..56a1546 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -659,10 +659,4 @@ namespace neopixel { Shortest, } - export function hsl(h: any, mapped_hue: number, s: any): number { - throw new Error("Function not implemented."); - } -} -function hsl(h: any, mapped_hue: number, s: any): number { - throw new Error("Function not implemented."); } From c597d44c1391c8ddee9ac26d128c97988b1af065 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 09:17:23 +0100 Subject: [PATCH 128/253] move translation into source code (bug) --- _locales/de/neopixel-jsdoc-strings.json | 17 --------- _locales/de/neopixel-strings.json | 35 +------------------ neopixel.ts | 46 +++++++++++++++++++++++-- pxt.json | 9 +---- 4 files changed, 46 insertions(+), 61 deletions(-) diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json index 234cb95..e69de29 100644 --- a/_locales/de/neopixel-jsdoc-strings.json +++ b/_locales/de/neopixel-jsdoc-strings.json @@ -1,17 +0,0 @@ -{ - "neopixel.create": "Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel.", - "neopixel.Strip.showColor": "Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf.", - "neopixel.Strip.setBrightness": "Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen.", - "neopixel.Strip.clear": "Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.easeBrightness": "Aktuelle Farben der NeoPixel je nach Pixelnr. abdunkeln.", - "neopixel.Strip.length": "Die Anzahl der NeoPixel, die der Treiber verwaltet.", - "neopixel.Strip.rotate": "Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.setPixelColorRange": "Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.shift": "Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden.", - "neopixel.Strip.showBarGraph": "Zeigt den angegebenen Wert in Bezug auf das gegebene Maximum als Balkendiagramm auf allen Neopixeln an.", - "neopixel.Strip.showRainbow": "Zeigt ein Regenbogenmuster auf allen NeoPixeln an.", - "neopixel.Strip.show": "Sendet alle Änderungen an die NeoPixel.", - "neopixel.rgb": "Erstellt eine RGB-Farbe", - "neopixel.hsv_picker": "Erstellt eine Farbe", - "neopixel.colors": "bekannte RGB-Farben" -} diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json index 41315dc..0967ef4 100644 --- a/_locales/de/neopixel-strings.json +++ b/_locales/de/neopixel-strings.json @@ -1,34 +1 @@ -{ - "NeoPixelColors.Black|block": "schwarz", - "NeoPixelColors.Blue|block": "blau", - "NeoPixelColors.Green|block": "grün", - "NeoPixelColors.Indigo|block": "indigo", - "NeoPixelColors.Orange|block": "orange", - "NeoPixelColors.Purple|block": "magenta", - "NeoPixelColors.Red|block": "rot", - "NeoPixelColors.Violet|block": "blauviolett", - "NeoPixelColors.White|block": "weiß", - "NeoPixelColors.Yellow|block": "gelb", - "NeoPixelMode.RGBW|block": "RGB+W", - "NeoPixelMode.RGB_RGB|block": "RGB", - "NeoPixelMode.RGB_GRB|block": "GRB", - "neopixel.Strip.clear|block": "%strip|ausschalten", - "neopixel.Strip.easeBrightness|block": "%strip|Anfang und Ende mit Verlauf abdunkeln", - "neopixel.Strip.length|block": "%strip|Länge", - "neopixel.Strip.rotate|block": "%strip|rotiere NeoPixel um %offset", - "neopixel.Strip.setBrightness|block": "%strip|setze Helligkeit %brightness", - "neopixel.Strip.setPixelColorRange|block": "%strip|setze Farbe(n) von %number NeoPixel(n) |an Position %pixeloffset|auf %rgb=neopixel_colors", - "neopixel.Strip.shift|block": "%strip|verschiebe NeoPixel um %offset", - "neopixel.Strip.showBarGraph|block": "%strip|zeige Balkendiagramm von Wert %value |mit Maximum %high", - "neopixel.Strip.showColor|block": "%strip|zeige Farbe %rgb=neopixel_colors", - "neopixel.Strip.showRainbow|block": "%strip|zeige Regenbogen von Farbton %startHue|bis %endHue", - "neopixel.Strip.show|block": "%strip|anzeigen", - "neopixel.colors|block": "%color", - "neopixel.create|block": "NeoPixels an Pin %pin|mit %numleds Pixeln", - "neopixel.Strip.power|block": "%strip|Stromverbrauch (mA)", - "neopixel.rgb|block": "rot %red|grün %green|blau %blue", - "neopixel.hsv_picker|block": "Farbe %hue", - "neopixel.Strip.setMatrixColor|block": "%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors", - "neopixel.Strip.setMatrixWidth|block": "%strip|setze Matrix Breite %width", - "{id:category}Neopixel": "NeoPixel" -} +{} diff --git a/neopixel.ts b/neopixel.ts index 56a1546..4cd35b3 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -3,24 +3,34 @@ */ enum NeoPixelColors { //% block=red + //% block.loc.de="rot" Red = 0xff0000, //% block=orange + //% block.loc.de="orange" Orange = 0xffa500, //% block=yellow + //% block.loc.de="gelb" Yellow = 0xffff00, //% block=green + //% block.loc.de="grün" Green = 0x00ff00, //% block=blue + //% block.loc.de="blau" Blue = 0x0000ff, //% block=indigo + //% block.loc.de="indigo" Indigo = 0x4b0082, //% block=violet + //% block.loc.de="violett" Violet = 0x8a2be2, //% block=purple + //% block.loc.de="magenta" Purple = 0xff00ff, //% block=white + //% block.loc.de="weiss" White = 0xffffff, //% block=black + //% block.loc.de="schwarz" Black = 0x000000, } @@ -29,10 +39,13 @@ enum NeoPixelColors { */ enum NeoPixelMode { //% block="RGB (GRB format)" + //% block.loc.de="GRB" RGB_GRB = 1, //% block="RGB+W" + //% block.loc.de="RGB+W" RGBW = 2, //% block="RGB (RGB format)" + //% block.loc.de="RGB" RGB_RGB = 3, } @@ -50,6 +63,7 @@ enum HiwonderPins { * Functions to operate NeoPixel strips. */ //% weight=5 color=#2699BF icon="\uf110" +//% block.loc.de="NeoPixel" namespace neopixel { /** * A NeoPixel strip @@ -69,6 +83,8 @@ namespace neopixel { * @param rgb RGB color of the LED */ //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" + //% block.loc.de="%strip|zeige Farbe %rgb=neopixel_colors" + //% jsdoc.loc.de="Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf." //% strip.defl=strip //% weight=85 blockGap=8 //% parts="neopixel" @@ -85,6 +101,8 @@ namespace neopixel { * @param endHue the end hue value for the rainbow */ //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% block.loc.de="%strip|zeige Regenbogen von Farbton %startHue|bis %endHue" + //% jsdoc.loc.de="Zeigt ein Regenbogenmuster auf allen NeoPixeln an." //% strip.defl=strip //% startHue.shadow="colorWheelHsvPicker" //% endHue.shadow="colorWheelHsvPicker" @@ -215,6 +233,8 @@ namespace neopixel { * @param rgb RGB color of the LED */ //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" + //% block.loc.de="%strip|setze Farbe(n) von %number NeoPixel(n) |an Position %pixeloffset|auf %rgb=neopixel_colors" + //% jsdoc.loc.de="Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% number.defl=1 //% number.min=1 @@ -238,6 +258,7 @@ namespace neopixel { * @param width number of pixels in a row */ //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" + //% block.loc.de="%strip|setze Matrix Breite %width" //% strip.defl=strip //% blockGap=8 //% weight=5 @@ -255,6 +276,7 @@ namespace neopixel { * @param rgb RGB color of the LED */ //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" + //% block.loc.de="%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors" //% strip.defl=strip //% weight=4 //% parts="neopixel" @@ -274,6 +296,8 @@ namespace neopixel { * Send all the changes to the strip. */ //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% block.loc.de="strip|anzeigen" + //% jsdoc.loc.de="Sendet alle Änderungen an die NeoPixel." //% strip.defl=strip //% weight=79 //% parts="neopixel" @@ -290,6 +314,8 @@ namespace neopixel { * You need to call ``show`` to make the changes visible. */ //% blockId="neopixel_clear" block="%strip|clear" + //% block.loc.de="strip|ausschalten" + //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% weight=76 //% parts="neopixel" @@ -303,6 +329,8 @@ namespace neopixel { * Gets the number of pixels declared on the strip */ //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% block.loc.de="%strip|Länge" + //% jsdoc.loc.de="Die Anzahl der NeoPixel, die der Treiber verwaltet." //% strip.defl=strip //% weight=60 //% subcategory=Stripe @@ -315,6 +343,8 @@ namespace neopixel { * @param brightness a measure of LED brightness in 0-255. eg: 255 */ //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% block.loc.de="%strip|setze Helligkeit %brightness" + //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen." //% brightness.defl=255 brightness.min=0 brightness.max=255 //% strip.defl=strip //% weight=59 @@ -328,11 +358,11 @@ namespace neopixel { * Apply brightness to current colors using a quadratic easing function. **/ //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% block.loc.de="%strip|Anfang und Ende mit Verlauf abdunkeln" //% strip.defl=strip //% weight=58 //% parts="neopixel" //% subcategory=Stripe - // TODO: Silvan: This function eases the brightness at start and end ! Not exactly what we need, is it? Shall we remove this? easeBrightness(): void { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; const buf = this.buf; @@ -367,6 +397,8 @@ namespace neopixel { * @param offset number of pixels to shift forward, eg: 1 */ //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% block.loc.de="%strip|verschiebe NeoPixel um %offset" + //% jsdoc.loc.de="Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% weight=40 //% parts="neopixel" @@ -387,6 +419,8 @@ namespace neopixel { * @param offset number of pixels to rotate forward, eg: 1 */ //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% block.loc.de="%strip|rotiere NeoPixel um %offset" + //% jsdoc.loc.de="Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% weight=39 //% parts="neopixel" @@ -417,6 +451,7 @@ namespace neopixel { * Estimates the electrical current (mA) consumed by the current light configuration. */ //% weight=9 blockId=neopixel_power block="%strip|power (mA)" + //% block.loc.de="%strip|Stromverbrauch (mA)" //% strip.defl=strip //% subcategory=Stripe power(): number { @@ -508,6 +543,8 @@ namespace neopixel { * @param numleds number of leds in the strip, eg: 24,30,60,64 */ //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" + //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln" + //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." //% weight=90 blockGap=8 //% parts="neopixel" //% subcategory=Stripe @@ -555,6 +592,8 @@ namespace neopixel { */ //% weight=85 blockGap=8 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% block.loc.de="rot %red|grün %green|blau %blue" + //% jsdoc.loc.de="Erstellt eine RGB-Farbe" //% red.defl=255 red.min=0 red.max=255 //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 @@ -568,6 +607,8 @@ namespace neopixel { */ //% weight=85 blockGap=8 //% blockId="neopixel_hsv" block="hue %hue" + //% block.loc.de="Farbe %hue" + //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" export function hsv_picker(hue: number): number { let mapped_hue = (hue * 360) / 255; @@ -579,6 +620,8 @@ namespace neopixel { */ //% weight=85 blockGap=8 //% blockId="neopixel_colors" block="%color" + //% block.loc.de="%color" + //% jsdoc.loc.de="bekannte RGB-Farben" export function colors(color: NeoPixelColors): number { return color; } @@ -658,5 +701,4 @@ namespace neopixel { CounterClockwise, Shortest, } - } diff --git a/pxt.json b/pxt.json index 758ad3a..1d9ad0a 100644 --- a/pxt.json +++ b/pxt.json @@ -7,14 +7,7 @@ "core": "file:../core", "ws2812b": "github:microsoft/pxt-ws2812b#v0.1.1" }, - "files": [ - "README.md", - "StartbitV2.ts", - "StartbitRGBLight.ts", - "neopixel.ts", - "_locales/de/neopixel-strings.json", - "_locales/de/neopixel-jsdoc-strings.json" - ], + "files": ["README.md", "StartbitV2.ts", "StartbitRGBLight.ts", "neopixel.ts"], "testFiles": ["test.ts", "neotest.ts"], "public": true, "supportedTargets": ["microbit"], From c09e72b2637747640ef3d48cfe84b3b47a4423cf Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 09:31:25 +0100 Subject: [PATCH 129/253] added missing % in loc.de --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 4cd35b3..7708c15 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,7 +296,7 @@ namespace neopixel { * Send all the changes to the strip. */ //% blockId="neopixel_show" block="%strip|show" blockGap=8 - //% block.loc.de="strip|anzeigen" + //% block.loc.de="%strip|anzeigen" //% jsdoc.loc.de="Sendet alle Änderungen an die NeoPixel." //% strip.defl=strip //% weight=79 From 569c1031b20b157f30483cbd4961a271cc0518dc Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 09:34:41 +0100 Subject: [PATCH 130/253] added another missing % in loc.de --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 7708c15..ce21009 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -314,7 +314,7 @@ namespace neopixel { * You need to call ``show`` to make the changes visible. */ //% blockId="neopixel_clear" block="%strip|clear" - //% block.loc.de="strip|ausschalten" + //% block.loc.de="%strip|ausschalten" //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% weight=76 From bc6d8d7a91d97f93d19db5d82f3adb41630e75d9 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 11:27:20 +0100 Subject: [PATCH 131/253] temp disable auto init --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ba70b96..135cfc5 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,5 +1,5 @@ // Auto init hiwonder board when extension is added -Informatiktheater.startbit_Init(); +// Informatiktheater.startbit_Init(); /* Informatiktheater package From a0db5b02696fc8ead18bd5ea1c85228a2dbafa0e Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 11:33:45 +0100 Subject: [PATCH 132/253] reactivate auto init but without audio alert --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 135cfc5..f467c83 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,5 +1,5 @@ // Auto init hiwonder board when extension is added -// Informatiktheater.startbit_Init(); +Informatiktheater.startbit_Init(); /* Informatiktheater package @@ -163,7 +163,7 @@ namespace Informatiktheater { basic.forever(() => { getHandleCmd(); if (0 < currentVoltage && currentVoltage < 6800) { - music.playTone(988, music.beat(BeatFraction.Whole)); + // music.playTone(988, music.beat(BeatFraction.Whole)); } }); basic.pause(2000); From 3401ce22c44fed889ac45f7bd8934eda8c4d8458 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 11:56:12 +0100 Subject: [PATCH 133/253] more jsdocs --- _locales/de/neopixel-jsdoc-strings.json | 0 _locales/de/neopixel-strings.json | 1 - neopixel.ts | 3 +++ 3 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 _locales/de/neopixel-jsdoc-strings.json delete mode 100644 _locales/de/neopixel-strings.json diff --git a/_locales/de/neopixel-jsdoc-strings.json b/_locales/de/neopixel-jsdoc-strings.json deleted file mode 100644 index e69de29..0000000 diff --git a/_locales/de/neopixel-strings.json b/_locales/de/neopixel-strings.json deleted file mode 100644 index 0967ef4..0000000 --- a/_locales/de/neopixel-strings.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/neopixel.ts b/neopixel.ts index ce21009..7780287 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -259,6 +259,7 @@ namespace neopixel { */ //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" //% block.loc.de="%strip|setze Matrix Breite %width" + //% jsdoc.loc.de="Setzt die Anzahl Pixel ein einer LED Matrize" //% strip.defl=strip //% blockGap=8 //% weight=5 @@ -277,6 +278,7 @@ namespace neopixel { */ //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" //% block.loc.de="%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors" + //% jsdoc.loc.de="Setzt die Farbe in einer LED Matrize im Bereich 0-255. Es muss anschliessend ``anzeigen`` ausgeführt werden, um die Änderung anzuzeigen." //% strip.defl=strip //% weight=4 //% parts="neopixel" @@ -452,6 +454,7 @@ namespace neopixel { */ //% weight=9 blockId=neopixel_power block="%strip|power (mA)" //% block.loc.de="%strip|Stromverbrauch (mA)" + //% jsdoc.loc.de="Schätzt den elektrischen Strom in mA der gewählten NeoPixel Konfiguration" //% strip.defl=strip //% subcategory=Stripe power(): number { From 462667938d44ac2b5505b9eab1638f44d05b888a Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 13:25:00 +0100 Subject: [PATCH 134/253] remove unknown trackargs from create fn --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 7780287..9be3e6e 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -551,7 +551,7 @@ namespace neopixel { //% weight=90 blockGap=8 //% parts="neopixel" //% subcategory=Stripe - //% trackArgs=0,2 + // trackArgs=0, 2 //% blockSetVariable=strip export function create(pin: HiwonderPins, numleds: number): Strip { let strip = new Strip(); From ceceaabf5622a2a448c7935fd68ef21a2e1146b6 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 13:34:16 +0100 Subject: [PATCH 135/253] remove white led support --- neopixel.ts | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 9be3e6e..e1f846a 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -523,21 +523,6 @@ namespace neopixel { } this.setBufferRGB(pixeloffset, red, green, blue); } - - private setPixelW(pixeloffset: number, white: number): void { - if (this._mode !== NeoPixelMode.RGBW) return; - - if (pixeloffset < 0 || pixeloffset >= this._length) return; - - pixeloffset = (pixeloffset + this.start) * 4; - - let br = this.brightness; - if (br < 255) { - white = (white * br) >> 8; - } - let buf = this.buf; - buf[pixeloffset + 3] = white; - } } /** @@ -551,6 +536,7 @@ namespace neopixel { //% weight=90 blockGap=8 //% parts="neopixel" //% subcategory=Stripe + // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled // trackArgs=0, 2 //% blockSetVariable=strip export function create(pin: HiwonderPins, numleds: number): Strip { From 1b63235aa912744b4840aab0ee2c18ae9ab8220a Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 15:27:16 +0100 Subject: [PATCH 136/253] limit max brithness --- neopixel.ts | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index e1f846a..491c655 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -65,6 +65,7 @@ enum HiwonderPins { //% weight=5 color=#2699BF icon="\uf110" //% block.loc.de="NeoPixel" namespace neopixel { + let leds_total = 0; /** * A NeoPixel strip */ @@ -342,12 +343,14 @@ namespace neopixel { /** * Set the brightness of the strip. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 + * The highest possible brightness level depends on the number of individual LED's set at ``create``. + * The brightness will be capped at this threshold. + * @param brightness a measure of LED brightness in 0-128. eg: 100 */ //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 //% block.loc.de="%strip|setze Helligkeit %brightness" - //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen." - //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-128). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." + //% brightness.defl=255 brightness.min=0 brightness.max=128 //% strip.defl=strip //% weight=59 //% parts="neopixel" @@ -493,7 +496,10 @@ namespace neopixel { let green = unpackG(rgb); let blue = unpackB(rgb); - const br = this.brightness; + const br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); if (br < 255) { red = (red * br) >> 8; green = (green * br) >> 8; @@ -515,7 +521,10 @@ namespace neopixel { let green = unpackG(rgb); let blue = unpackB(rgb); - let br = this.brightness; + const br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); if (br < 255) { red = (red * br) >> 8; green = (green * br) >> 8; @@ -525,6 +534,14 @@ namespace neopixel { } } + function total_brightness_limit(): number { + // a WS2812B LED has a current of about 60mA at full brightness with white color + // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. + const br = Math.idiv(700 * 255, leds_total * 60) & 0xff; + console.log("Max brightness: " + br); + return br; + } + /** * Create a new NeoPixel driver for `numleds` LEDs. * @param pin the pin where the neopixel is connected on the Hiwonder board @@ -540,6 +557,7 @@ namespace neopixel { // trackArgs=0, 2 //% blockSetVariable=strip export function create(pin: HiwonderPins, numleds: number): Strip { + leds_total += numleds; let strip = new Strip(); const mode = NeoPixelMode.RGB_GRB; let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; From 57fca7ca3f56069b53ef47060ce8f154495ddeae Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 15:38:52 +0100 Subject: [PATCH 137/253] put back audio alert; edited readme --- README.md | 4 +--- StartbitV2.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e4f2c2f..f20e036 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ # Informatiktheater -Adapted code blocks for Hiwonder extension board based on [StartbitV2](https://github.com/Hiwonder/StartbitV2). -Some blocks were removed and the remaining ones translated into German. -A few new blocks were added to communicate with the attached hardware (e.g. mp3player). +Adapted code blocks for Hiwonder extension board based on [StartbitV2](https://github.com/Hiwonder/StartbitV2) including 3-party libraries for NeoPixel. diff --git a/StartbitV2.ts b/StartbitV2.ts index f467c83..ba70b96 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -163,7 +163,7 @@ namespace Informatiktheater { basic.forever(() => { getHandleCmd(); if (0 < currentVoltage && currentVoltage < 6800) { - // music.playTone(988, music.beat(BeatFraction.Whole)); + music.playTone(988, music.beat(BeatFraction.Whole)); } }); basic.pause(2000); From 32748d0cd6f4df7693eb3d3744ba8786817cdf20 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 15:43:14 +0100 Subject: [PATCH 138/253] hide power estimation block --- neopixel.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 491c655..47dc52a 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -455,11 +455,6 @@ namespace neopixel { /** * Estimates the electrical current (mA) consumed by the current light configuration. */ - //% weight=9 blockId=neopixel_power block="%strip|power (mA)" - //% block.loc.de="%strip|Stromverbrauch (mA)" - //% jsdoc.loc.de="Schätzt den elektrischen Strom in mA der gewählten NeoPixel Konfiguration" - //% strip.defl=strip - //% subcategory=Stripe power(): number { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; const end = this.start + this._length; From 37a3c7e97f4f62822bccf772aec264389f45c649 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 16:09:22 +0100 Subject: [PATCH 139/253] add smartMatrix lib --- neopixel.ts | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index 47dc52a..0d603af 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -704,3 +704,242 @@ namespace neopixel { Shortest, } } + +/** + * Micro:Bit makeCode extension for neopixel.was2812b matrices + * + * + */ + +//**********************************************// +// library for NeoPixel Displays/Matrices // +// // +//Written by Sjors Smit // +//June 2020 // +// // +//**********************************************// + +//% weight=6 color=#00CC60 icon="\uf110" +//% groups=["Setup", "Tools", "PixelControl"] +namespace Matrix { + /** + * A Matrix made of ws2812b LEDs + */ + export class Matrix { + strip: neopixel.Strip; + Width: number; + Height: number; + + //%blockId="Matrix_show" block="%matrix| anzeigen" + //%weight=90 group="Tools" + show(): void { + this.strip.show(); + } + //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-255) %setpoint" + //%weight=80 group="Setup" + //%setpoint.defl=32 + Brightness(setpoint: number): void { + this.strip.setBrightness(setpoint); + } + //%blockId="Matrix_clear" block="%matrix| löschen" + //%weight=80 group="Tools" + clear(): void { + this.strip.clear(); + } + + //%blockId="Matrix_setPixel" block="%matrix| setze das Pixel x %x| y %y| auf die Farbe %colour" + //%weight=80 group="PixelControl" + //%colour.shadow=neopixel_colors + setPixel(x: number, y: number, colour: number): void { + if (x < 0 || x > this.Width || y < 0 || y > this.Height) { + return; + } //If the pixel does not fit on screen, do not draw it (to avoid aliasing) + if (!(x % 2)) { + this.strip.setPixelColor(y + x * this.Height, colour); + } //Because of the zig-zag formation of the panel all even rows (including 0) are drawn top to bottom + else { + this.strip.setPixelColor(this.Height - y + x * this.Height, colour); + } //While all odd rows are drawn bottom to top + } + /** + * scroll text on the matrix + */ + //%blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (0 - 1024) %speed| Farbe %colour" + //%weight=75 group="PixelControl" + //%colour.shadow=neopixel_colors + //%speed.min=0 speed.max=1024 speed.defl=512 + scrollText(text: string, speed: number, colour: number): void { + this.strip.clear(); + for (let Xpos = this.Width; Xpos > -6 * text.length; Xpos--) { + //for loop to scroll across the entire matrix + for (let letter = 0; letter < text.length; letter++) { + //for loop to retrieve all the letters from te text + let bitmap = getLettermap(text.charAt(letter)); + this.drawBitmap(bitmap, Xpos + 6 * letter, 0, 6, 8, colour); + } + this.strip.show(); + basic.pause(2000 / speed); + this.strip.clear(); + } + } + //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" + //%weight=70 group="PixelControl" + //% colour.shadow=neopixel.colors + drawBitmap( + bitmap: number[], + x: number, + y: number, + width: number, + height: number, + colour: number + ): void { + for (let bitmask = 0; bitmask < width; bitmask++) { + if (!((x + bitmask) % 2)) { + //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top + for (let Ypos = height; Ypos >= 0; Ypos--) { + if (bitmap[Ypos] & (0x80 >> bitmask)) { + //draw the pixel when there is a "1" in the bitmap + this.strip.setPixelColor( + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } else { + //else draw from top to bottom + for (let Ypos = 0; Ypos < this.Height; Ypos++) { + if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { + this.strip.setPixelColor( + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } + } + } + //%blockId="Matrix_drawBitmap2" block="%matrix zeichne bitmap %bitmap bei x %xoffset| y %yoffset| mit Breite %width| Höhe %height in der Farbe %colour" + //%weight=70 group="PixelControl" + //% colour.shadow=neopixel.colors + drawBitmap2( + bitmap: number[], + xoffset: number, + yoffset: number, + width: number, + height: number, + colour: number, + doMirror: boolean = false + ): void { + let mirrored = 0; + if (doMirror) { + mirrored = 1; + } + if (width % 2) { + //To properly enable mirror, width has to be even, so if uneven width gets added to by 1 + width++; + } + //Setting end value of k to equal the width of the image to shift the bitmask to the correct position. for drawing the x-axis + for (let k = 0; k < width; k++) { + //Due to the zig-zag pattern of the matrix every odd value on the matrix has to be drawn from bottom to top, and the others top to bottom. + if (!((xoffset + k + mirrored) % 2)) { + //Value of j to select the values in the array to draw on the y-axis + for (let j = 0; j < height; j++) { + //only draw a pixel when there is a '1' in the bitmap, without drawing a "black" pixel when there is a '0', allowing layering of bitmaps. + if ( + bitmap[j] & (0b1 << (width - k - 1)) && + j + yoffset < this.Height && + yoffset + j >= 0 + ) { + //Draw the actual pixel at the position determined by the k, j , xoffset and yoffset values. + this.strip.setPixelColor( + ((mirrored - 1) * -k + xoffset + (width - k - 1) * mirrored) * + this.Height + + j + + yoffset, + colour + ); + } + } + } + //Drawing the odd lines top to bottom. + else { + for (let j = 0; j < height; j++) { + if ( + bitmap[j] & (0b1 << (width - k - 1)) && + yoffset + j < this.Height && + yoffset + j >= 0 + ) { + this.strip.setPixelColor( + ((mirrored - 1) * -k + xoffset + (width - k - 1) * mirrored) * + this.Height + + (this.Height - j - yoffset - 1), + colour + ); + } + } + } + } + } + } + + /** + * Create a new matrix object + * @param pin the pin to which the matrix is connected + * @param matrixWidth the amount of leds horizontally + * @param matrixheight the amount of leds vertically + */ + //%blockId="Matrix_Create" block="Matrix at pin %pin|with a width of %matrixWidth|height of %matrixheight" + //%weight=100 blockGap=8 group="Setup" + //%parts="SmartMatrix" + //%matrixWidth.defl=32 matrixheight.defl=8 + //%blockSetVariable=matrix + export function create( + pin: DigitalPin, + matrixWidth: number, + matrixHeight: number + ): Matrix { + let matrix = new Matrix(); + matrix.strip = neopixel.create(pin, matrixHeight * matrixWidth); + matrix.Width = matrixWidth; + matrix.Height = matrixHeight; + + return matrix; + } + //Take in a string-character and return a bitmap to draw on the display + export function getLettermap(char: string): number[] { + let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array + if (offset >= 0) { + for (let i = 0; i < 8; i++) { + //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. + letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); + } + } + return letterMap; + } +} +const font8x3 = hex` + 0000000000000000 1038381010001000 6C6C480000000000 00287C28287C2800 + 2038403008701000 64640810204C4C00 2050502054483400 3030200000000000 + 1020202020201000 2010101010102000 0028387C38280000 0010107C10100000 + 0000000000303020 0000007C00000000 0000000000303000 0004081020400000 + 38444C5464443800 1030101010103800 3844041820407C00 3844043804443800 + 081828487C080800 7C40407804443800 1820407844443800 7C04081020202000 + 3844443844443800 3844443C04083000 0000303000303000 0000303000303020 + 0810204020100800 00007C00007C0000 2010080408102000 3844041810001000 + 38445C545C403800 384444447C444400 7844447844447800 3844404040443800 + 7844444444447800 7C40407840407C00 7C40407840404000 3844405C44443C00 + 4444447C44444400 3810101010103800 0404040444443800 4448506050484400 + 4040404040407C00 446C544444444400 4464544C44444400 3844444444443800 + 7844447840404000 3844444454483400 7844447848444400 3844403804443800 + 7C10101010101000 4444444444443800 4444444444281000 4444545454542800 + 4444281028444400 4444442810101000 7808102040407800 3820202020203800 + 0040201008040000 3808080808083800 1028440000000000 00000000000000FC + 3030100000000000 000038043C443C00 4040784444447800 0000384440443800 + 04043C4444443C00 0000384478403800 1820207820202000 00003C44443C0438 + 4040704848484800 1000101010101800 0800180808084830 4040485060504800 + 1010101010101800 0000685454444400 0000704848484800 0000384444443800 + 0000784444447840 00003C4444443C04 0000582420207000 0000384038043800 + 0020782020281000 0000484848582800 0000444444281000 00004444547C2800 + 0000484830484800 0000484848381060 0000780830407800 1820206020201800 + 1010100010101000 3008080C08083000 2850000000000000`; From a7465b4f01448cb9204590e1de04484d91dd3d53 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 16:17:37 +0100 Subject: [PATCH 140/253] use hiwonder pin --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 0d603af..31b2b8c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -894,7 +894,7 @@ namespace Matrix { //%matrixWidth.defl=32 matrixheight.defl=8 //%blockSetVariable=matrix export function create( - pin: DigitalPin, + pin: HiwonderPins, matrixWidth: number, matrixHeight: number ): Matrix { From d698984d401994884e86e33c4e101bed6e2a26ae Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 16:40:38 +0100 Subject: [PATCH 141/253] neopixel shadow --- neopixel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 31b2b8c..56d0981 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -784,7 +784,7 @@ namespace Matrix { } //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" //%weight=70 group="PixelControl" - //% colour.shadow=neopixel.colors + //%colour.shadow=neopixel_colors drawBitmap( bitmap: number[], x: number, @@ -820,7 +820,7 @@ namespace Matrix { } //%blockId="Matrix_drawBitmap2" block="%matrix zeichne bitmap %bitmap bei x %xoffset| y %yoffset| mit Breite %width| Höhe %height in der Farbe %colour" //%weight=70 group="PixelControl" - //% colour.shadow=neopixel.colors + //%colour.shadow=neopixel_colors drawBitmap2( bitmap: number[], xoffset: number, From 4650d8962f64dad5eedc7d69eff16e447bbef36b Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 20 Mar 2023 17:11:44 +0100 Subject: [PATCH 142/253] limit scroll text speed --- neopixel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 56d0981..1d370b0 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -764,10 +764,10 @@ namespace Matrix { /** * scroll text on the matrix */ - //%blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (0 - 1024) %speed| Farbe %colour" + //%blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (0 - 100) %speed| Farbe %colour" //%weight=75 group="PixelControl" //%colour.shadow=neopixel_colors - //%speed.min=0 speed.max=1024 speed.defl=512 + //%speed.min=0 speed.max=100 speed.defl=50 scrollText(text: string, speed: number, colour: number): void { this.strip.clear(); for (let Xpos = this.Width; Xpos > -6 * text.length; Xpos--) { From 47597350260e179c99e1d2d036ddd8a1afb60feb Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 09:01:50 +0100 Subject: [PATCH 143/253] remove neopixel matrix functions --- neopixel.ts | 44 +------------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 1d370b0..bdd4598 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -77,7 +77,6 @@ namespace neopixel { start: number; // start offset in LED strip _length: number; // number of LEDs _mode: NeoPixelMode; - _matrixWidth: number; // number of leds in a matrix - if any /** * Shows all LEDs to a given color (range 0-255 for r, g, b). @@ -254,47 +253,6 @@ namespace neopixel { this.setPixelRGB(pixeloffset >> 0, rgb >> 0); } - /** - * Sets the number of pixels in a matrix shaped strip - * @param width number of pixels in a row - */ - //% blockId=neopixel_set_matrix_width block="%strip|set matrix width %width" - //% block.loc.de="%strip|setze Matrix Breite %width" - //% jsdoc.loc.de="Setzt die Anzahl Pixel ein einer LED Matrize" - //% strip.defl=strip - //% blockGap=8 - //% weight=5 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixWidth(width: number) { - this._matrixWidth = Math.min(this._length, width >> 0); - } - - /** - * Set LED to a given color (range 0-255 for r, g, b) in a matrix shaped strip - * You need to call ``show`` to make the changes visible. - * @param x horizontal position - * @param y horizontal position - * @param rgb RGB color of the LED - */ - //% blockId="neopixel_set_matrix_color" block="%strip|set matrix color at x %x|y %y|to %rgb=neopixel_colors" - //% block.loc.de="%strip|setze Matrix Farbe an Position x %x|y %y|auf %rgb=neopixel_colors" - //% jsdoc.loc.de="Setzt die Farbe in einer LED Matrize im Bereich 0-255. Es muss anschliessend ``anzeigen`` ausgeführt werden, um die Änderung anzuzeigen." - //% strip.defl=strip - //% weight=4 - //% parts="neopixel" - //% subcategory=Matrix - setMatrixColor(x: number, y: number, rgb: number) { - if (this._matrixWidth <= 0) return; // not a matrix, ignore - x = x >> 0; - y = y >> 0; - rgb = rgb >> 0; - const cols = Math.idiv(this._length, this._matrixWidth); - if (x < 0 || x >= this._matrixWidth || y < 0 || y >= cols) return; - let i = x + y * this._matrixWidth; - this.setPixelColor(i, rgb); - } - /** * Send all the changes to the strip. */ @@ -506,6 +464,7 @@ namespace neopixel { this.setBufferRGB(i * stride, red, green, blue); } } + private setPixelRGB(pixeloffset: number, rgb: number): void { if (pixeloffset < 0 || pixeloffset >= this._length) return; @@ -560,7 +519,6 @@ namespace neopixel { strip.start = 0; strip._length = numleds; strip._mode = mode || NeoPixelMode.RGB_GRB; - strip._matrixWidth = 0; strip.setBrightness(128); // TODO: How can we solve this more elegant? When trying to cast, // we can't use string literals here and can't change DigitalPin to non constant enum From eacc74384d82399d51e0975bb11c36e715ac6e9c Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 09:25:01 +0100 Subject: [PATCH 144/253] move smartmatrix stuff in neopixel NS --- neopixel.ts | 71 ++++++++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index bdd4598..be68e41 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -661,53 +661,36 @@ namespace neopixel { CounterClockwise, Shortest, } -} -/** - * Micro:Bit makeCode extension for neopixel.was2812b matrices - * - * - */ - -//**********************************************// -// library for NeoPixel Displays/Matrices // -// // -//Written by Sjors Smit // -//June 2020 // -// // -//**********************************************// - -//% weight=6 color=#00CC60 icon="\uf110" -//% groups=["Setup", "Tools", "PixelControl"] -namespace Matrix { - /** - * A Matrix made of ws2812b LEDs - */ export class Matrix { strip: neopixel.Strip; Width: number; Height: number; //%blockId="Matrix_show" block="%matrix| anzeigen" - //%weight=90 group="Tools" + //%weight=90 + //% subcategory=Matrix show(): void { this.strip.show(); } //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-255) %setpoint" - //%weight=80 group="Setup" + //%weight=80 //%setpoint.defl=32 + //% subcategory=Matrix Brightness(setpoint: number): void { this.strip.setBrightness(setpoint); } //%blockId="Matrix_clear" block="%matrix| löschen" - //%weight=80 group="Tools" + //%weight=80 + //% subcategory=Matrix clear(): void { this.strip.clear(); } //%blockId="Matrix_setPixel" block="%matrix| setze das Pixel x %x| y %y| auf die Farbe %colour" - //%weight=80 group="PixelControl" + //%weight=80 //%colour.shadow=neopixel_colors + //% subcategory=Matrix setPixel(x: number, y: number, colour: number): void { if (x < 0 || x > this.Width || y < 0 || y > this.Height) { return; @@ -723,7 +706,8 @@ namespace Matrix { * scroll text on the matrix */ //%blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (0 - 100) %speed| Farbe %colour" - //%weight=75 group="PixelControl" + //%weight=75 + //% subcategory=Matrix //%colour.shadow=neopixel_colors //%speed.min=0 speed.max=100 speed.defl=50 scrollText(text: string, speed: number, colour: number): void { @@ -741,7 +725,8 @@ namespace Matrix { } } //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" - //%weight=70 group="PixelControl" + //%weight=70 + //% subcategory=Matrix //%colour.shadow=neopixel_colors drawBitmap( bitmap: number[], @@ -777,7 +762,8 @@ namespace Matrix { } } //%blockId="Matrix_drawBitmap2" block="%matrix zeichne bitmap %bitmap bei x %xoffset| y %yoffset| mit Breite %width| Höhe %height in der Farbe %colour" - //%weight=70 group="PixelControl" + //%weight=70 + //% subcategory=Matrix //%colour.shadow=neopixel_colors drawBitmap2( bitmap: number[], @@ -847,11 +833,12 @@ namespace Matrix { * @param matrixheight the amount of leds vertically */ //%blockId="Matrix_Create" block="Matrix at pin %pin|with a width of %matrixWidth|height of %matrixheight" - //%weight=100 blockGap=8 group="Setup" - //%parts="SmartMatrix" + //%weight=100 blockGap=8 + //% subcategory=Matrix + //%parts="neopixel" //%matrixWidth.defl=32 matrixheight.defl=8 //%blockSetVariable=matrix - export function create( + export function create_matrix( pin: HiwonderPins, matrixWidth: number, matrixHeight: number @@ -863,19 +850,21 @@ namespace Matrix { return matrix; } - //Take in a string-character and return a bitmap to draw on the display - export function getLettermap(char: string): number[] { - let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; - let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array - if (offset >= 0) { - for (let i = 0; i < 8; i++) { - //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. - letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); - } +} + +//Take in a string-character and return a bitmap to draw on the display +export function getLettermap(char: string): number[] { + let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array + if (offset >= 0) { + for (let i = 0; i < 8; i++) { + //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. + letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); } - return letterMap; } + return letterMap; } + const font8x3 = hex` 0000000000000000 1038381010001000 6C6C480000000000 00287C28287C2800 2038403008701000 64640810204C4C00 2050502054483400 3030200000000000 From fa25de4508e0f5c041dcb8e01d1357b3dd8b90d6 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 09:35:05 +0100 Subject: [PATCH 145/253] move getlettermap into neopixel NS --- neopixel.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index be68e41..20333c4 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -850,21 +850,21 @@ namespace neopixel { return matrix; } -} - -//Take in a string-character and return a bitmap to draw on the display -export function getLettermap(char: string): number[] { - let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; - let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array - if (offset >= 0) { - for (let i = 0; i < 8; i++) { - //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. - letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); + //Take in a string-character and return a bitmap to draw on the display + export function getLettermap(char: string): number[] { + let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array + if (offset >= 0) { + for (let i = 0; i < 8; i++) { + //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. + letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); + } } + return letterMap; } - return letterMap; } + const font8x3 = hex` 0000000000000000 1038381010001000 6C6C480000000000 00287C28287C2800 2038403008701000 64640810204C4C00 2050502054483400 3030200000000000 From a1575a47dee9ca6c21dd98141fe50231a6f18d4e Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 10:00:35 +0100 Subject: [PATCH 146/253] grouping for neopixels --- neopixel.ts | 67 +++++++++++++++++------------------------------------ 1 file changed, 21 insertions(+), 46 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 20333c4..80388a7 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -64,6 +64,7 @@ enum HiwonderPins { */ //% weight=5 color=#2699BF icon="\uf110" //% block.loc.de="NeoPixel" +//groups=['Setup', 'Features', 'Kontrolle'] namespace neopixel { let leds_total = 0; /** @@ -88,6 +89,7 @@ namespace neopixel { //% strip.defl=strip //% weight=85 blockGap=8 //% parts="neopixel" + //% group="Kontrolle" //% subcategory=Stripe showColor(rgb: number) { rgb = rgb >> 0; @@ -109,6 +111,7 @@ namespace neopixel { //% weight=85 blockGap=8 //% parts="neopixel" //% subcategory=Stripe + //% group="Features" showRainbow(startHue: number = 1, endHue: number = 255) { if (this._length <= 0) return; @@ -187,44 +190,6 @@ namespace neopixel { this.show(); } - // /** - // * Displays a vertical bar graph based on the `value` and `high` value. - // * If `high` is 0, the chart gets adjusted automatically. - // * @param value current value to plot - // * @param high maximum value, eg: 255 - // */ - // //% weight=84 - // //% blockId=neopixel_show_bar_graph block="%strip|show bar graph of %value|up to %high" - // //% strip.defl=strip - // //% icon="\uf080" - // //% parts="neopixel" - // //% subcategory=Stripe - showBarGraph(value: number, high: number): void { - if (high <= 0) { - this.clear(); - this.setPixelColor(0, NeoPixelColors.Yellow); - this.show(); - return; - } - - value = Math.abs(value); - const n = this._length; - const n1 = n - 1; - let v = Math.idiv(value * n, high); - if (v == 0) { - this.setPixelColor(0, 0x666600); - for (let i = 1; i < n; ++i) this.setPixelColor(i, 0); - } else { - for (let i = 0; i < n; ++i) { - if (i <= v) { - const b = Math.idiv(i * 255, n1); - this.setPixelColor(i, neopixel.rgb(b, 0, 255 - b)); - } else this.setPixelColor(i, 0); - } - } - this.show(); - } - /** * Set LED to a given color (range 0-255 for r, g, b). * You need to call ``show`` to make the changes visible. @@ -243,6 +208,7 @@ namespace neopixel { //% weight=80 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { for (let i = 0; i < number; i++) { this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); @@ -263,6 +229,7 @@ namespace neopixel { //% weight=79 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); @@ -281,6 +248,7 @@ namespace neopixel { //% weight=76 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" clear(): void { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; this.buf.fill(0, this.start * stride, this._length * stride); @@ -295,6 +263,7 @@ namespace neopixel { //% strip.defl=strip //% weight=60 //% subcategory=Stripe + //% group="Setup" length() { return this._length; } @@ -313,6 +282,7 @@ namespace neopixel { //% weight=59 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" setBrightness(brightness: number): void { this.brightness = brightness & 0xff; } @@ -326,6 +296,7 @@ namespace neopixel { //% weight=58 //% parts="neopixel" //% subcategory=Stripe + //% group="Features" easeBrightness(): void { const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; const buf = this.buf; @@ -366,6 +337,7 @@ namespace neopixel { //% weight=40 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" shift(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; @@ -388,6 +360,7 @@ namespace neopixel { //% weight=39 //% parts="neopixel" //% subcategory=Stripe + //% group="Kontrolle" rotate(offset: number = 1): void { offset = offset >> 0; const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; @@ -398,12 +371,6 @@ namespace neopixel { ); } - /** - * Set the pin where the neopixel is connected, defaults to P0. - */ - //% weight=10 - //% parts="neopixel" - //% subcategory=Stripe setPin(pin: DigitalPin): void { this.pin = pin; pins.digitalWritePin(this.pin, 0); @@ -510,6 +477,7 @@ namespace neopixel { // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled // trackArgs=0, 2 //% blockSetVariable=strip + //% group="Setup" export function create(pin: HiwonderPins, numleds: number): Strip { leds_total += numleds; let strip = new Strip(); @@ -670,6 +638,7 @@ namespace neopixel { //%blockId="Matrix_show" block="%matrix| anzeigen" //%weight=90 //% subcategory=Matrix + //% group="Kontrolle" show(): void { this.strip.show(); } @@ -677,12 +646,14 @@ namespace neopixel { //%weight=80 //%setpoint.defl=32 //% subcategory=Matrix + //% group="Kontrolle" Brightness(setpoint: number): void { this.strip.setBrightness(setpoint); } //%blockId="Matrix_clear" block="%matrix| löschen" //%weight=80 //% subcategory=Matrix + //% group="Kontrolle" clear(): void { this.strip.clear(); } @@ -691,6 +662,7 @@ namespace neopixel { //%weight=80 //%colour.shadow=neopixel_colors //% subcategory=Matrix + //% group="Kontrolle" setPixel(x: number, y: number, colour: number): void { if (x < 0 || x > this.Width || y < 0 || y > this.Height) { return; @@ -710,6 +682,7 @@ namespace neopixel { //% subcategory=Matrix //%colour.shadow=neopixel_colors //%speed.min=0 speed.max=100 speed.defl=50 + //% group="Features" scrollText(text: string, speed: number, colour: number): void { this.strip.clear(); for (let Xpos = this.Width; Xpos > -6 * text.length; Xpos--) { @@ -728,6 +701,7 @@ namespace neopixel { //%weight=70 //% subcategory=Matrix //%colour.shadow=neopixel_colors + //% group="Features" drawBitmap( bitmap: number[], x: number, @@ -765,6 +739,7 @@ namespace neopixel { //%weight=70 //% subcategory=Matrix //%colour.shadow=neopixel_colors + //% group="Features" drawBitmap2( bitmap: number[], xoffset: number, @@ -838,6 +813,7 @@ namespace neopixel { //%parts="neopixel" //%matrixWidth.defl=32 matrixheight.defl=8 //%blockSetVariable=matrix + //% group="Setup" export function create_matrix( pin: HiwonderPins, matrixWidth: number, @@ -851,7 +827,7 @@ namespace neopixel { return matrix; } //Take in a string-character and return a bitmap to draw on the display - export function getLettermap(char: string): number[] { + function getLettermap(char: string): number[] { let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array if (offset >= 0) { @@ -864,7 +840,6 @@ namespace neopixel { } } - const font8x3 = hex` 0000000000000000 1038381010001000 6C6C480000000000 00287C28287C2800 2038403008701000 64640810204C4C00 2050502054483400 3030200000000000 From ae05abae12b5e54eeef63dfd45a43e75664660d3 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 10:25:31 +0100 Subject: [PATCH 147/253] no gaps --- neopixel.ts | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 80388a7..7057e33 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -62,9 +62,9 @@ enum HiwonderPins { /** * Functions to operate NeoPixel strips. */ -//% weight=5 color=#2699BF icon="\uf110" +//% weight=5 icon="\uf110" //% block.loc.de="NeoPixel" -//groups=['Setup', 'Features', 'Kontrolle'] +//groups=['Kontrolle', 'Features', 'Setup'] namespace neopixel { let leds_total = 0; /** @@ -87,7 +87,7 @@ namespace neopixel { //% block.loc.de="%strip|zeige Farbe %rgb=neopixel_colors" //% jsdoc.loc.de="Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf." //% strip.defl=strip - //% weight=85 blockGap=8 + //% weight=98 //% parts="neopixel" //% group="Kontrolle" //% subcategory=Stripe @@ -108,7 +108,7 @@ namespace neopixel { //% strip.defl=strip //% startHue.shadow="colorWheelHsvPicker" //% endHue.shadow="colorWheelHsvPicker" - //% weight=85 blockGap=8 + //% weight=97 //% parts="neopixel" //% subcategory=Stripe //% group="Features" @@ -204,7 +204,6 @@ namespace neopixel { //% number.defl=1 //% number.min=1 //% number.min=255 - //% blockGap=8 //% weight=80 //% parts="neopixel" //% subcategory=Stripe @@ -222,11 +221,11 @@ namespace neopixel { /** * Send all the changes to the strip. */ - //% blockId="neopixel_show" block="%strip|show" blockGap=8 + //% blockId="neopixel_show" block="%strip|show" //% block.loc.de="%strip|anzeigen" //% jsdoc.loc.de="Sendet alle Änderungen an die NeoPixel." //% strip.defl=strip - //% weight=79 + //% weight=10 //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" @@ -245,7 +244,7 @@ namespace neopixel { //% block.loc.de="%strip|ausschalten" //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip - //% weight=76 + //% weight=9 //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" @@ -257,7 +256,7 @@ namespace neopixel { /** * Gets the number of pixels declared on the strip */ - //% blockId="neopixel_length" block="%strip|length" blockGap=8 + //% blockId="neopixel_length" block="%strip|length" //% block.loc.de="%strip|Länge" //% jsdoc.loc.de="Die Anzahl der NeoPixel, die der Treiber verwaltet." //% strip.defl=strip @@ -274,12 +273,12 @@ namespace neopixel { * The brightness will be capped at this threshold. * @param brightness a measure of LED brightness in 0-128. eg: 100 */ - //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" blockGap=8 + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" //% block.loc.de="%strip|setze Helligkeit %brightness" //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-128). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." //% brightness.defl=255 brightness.min=0 brightness.max=128 //% strip.defl=strip - //% weight=59 + //% weight=99 //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" @@ -290,7 +289,7 @@ namespace neopixel { /** * Apply brightness to current colors using a quadratic easing function. **/ - //% blockId="neopixel_each_brightness" block="%strip|ease brightness" blockGap=8 + //% blockId="neopixel_each_brightness" block="%strip|ease brightness" //% block.loc.de="%strip|Anfang und Ende mit Verlauf abdunkeln" //% strip.defl=strip //% weight=58 @@ -330,7 +329,7 @@ namespace neopixel { * You need to call ``show`` to make the changes visible. * @param offset number of pixels to shift forward, eg: 1 */ - //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" blockGap=8 + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" //% block.loc.de="%strip|verschiebe NeoPixel um %offset" //% jsdoc.loc.de="Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip @@ -353,7 +352,7 @@ namespace neopixel { * You need to call ``show`` to make the changes visible. * @param offset number of pixels to rotate forward, eg: 1 */ - //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" blockGap=8 + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" //% block.loc.de="%strip|rotiere NeoPixel um %offset" //% jsdoc.loc.de="Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip @@ -471,7 +470,7 @@ namespace neopixel { //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln" //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." - //% weight=90 blockGap=8 + //% weight=90 //% parts="neopixel" //% subcategory=Stripe // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled @@ -518,7 +517,7 @@ namespace neopixel { * @param g green channel * @param b blue channel */ - //% weight=85 blockGap=8 + //% weight=85 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" //% block.loc.de="rot %red|grün %green|blau %blue" //% jsdoc.loc.de="Erstellt eine RGB-Farbe" @@ -533,7 +532,7 @@ namespace neopixel { * creates a color from hsv color picker * @param hue color */ - //% weight=85 blockGap=8 + //% weight=85 //% blockId="neopixel_hsv" block="hue %hue" //% block.loc.de="Farbe %hue" //% jsdoc.loc.de="Erstellt eine Farbe" @@ -546,7 +545,7 @@ namespace neopixel { /** * Gets the RGB value of a known color */ - //% weight=85 blockGap=8 + //% weight=85 //% blockId="neopixel_colors" block="%color" //% block.loc.de="%color" //% jsdoc.loc.de="bekannte RGB-Farben" @@ -636,7 +635,7 @@ namespace neopixel { Height: number; //%blockId="Matrix_show" block="%matrix| anzeigen" - //%weight=90 + //%weight=10 //% subcategory=Matrix //% group="Kontrolle" show(): void { @@ -651,7 +650,7 @@ namespace neopixel { this.strip.setBrightness(setpoint); } //%blockId="Matrix_clear" block="%matrix| löschen" - //%weight=80 + //%weight=8 //% subcategory=Matrix //% group="Kontrolle" clear(): void { @@ -659,7 +658,7 @@ namespace neopixel { } //%blockId="Matrix_setPixel" block="%matrix| setze das Pixel x %x| y %y| auf die Farbe %colour" - //%weight=80 + //%weight=70 //%colour.shadow=neopixel_colors //% subcategory=Matrix //% group="Kontrolle" @@ -808,7 +807,7 @@ namespace neopixel { * @param matrixheight the amount of leds vertically */ //%blockId="Matrix_Create" block="Matrix at pin %pin|with a width of %matrixWidth|height of %matrixheight" - //%weight=100 blockGap=8 + //%weight=100 //% subcategory=Matrix //%parts="neopixel" //%matrixWidth.defl=32 matrixheight.defl=8 From f710faef0cfcdaf9dbb8332a92813a3dc3677650 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 12:36:23 +0100 Subject: [PATCH 148/253] bugfix for setPixel() in Matrix uneven cols --- neopixel.ts | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 7057e33..abe56d7 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -62,7 +62,7 @@ enum HiwonderPins { /** * Functions to operate NeoPixel strips. */ -//% weight=5 icon="\uf110" +//% weight=5 color=#2896ff icon="\uf110" //% block.loc.de="NeoPixel" //groups=['Kontrolle', 'Features', 'Setup'] namespace neopixel { @@ -641,14 +641,17 @@ namespace neopixel { show(): void { this.strip.show(); } - //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-255) %setpoint" + //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-128) %setpoint" //%weight=80 //%setpoint.defl=32 + //%setpoint.min=0 + //%setpoint.max=128 //% subcategory=Matrix //% group="Kontrolle" Brightness(setpoint: number): void { this.strip.setBrightness(setpoint); } + //%blockId="Matrix_clear" block="%matrix| löschen" //%weight=8 //% subcategory=Matrix @@ -657,21 +660,35 @@ namespace neopixel { this.strip.clear(); } - //%blockId="Matrix_setPixel" block="%matrix| setze das Pixel x %x| y %y| auf die Farbe %colour" + /** + * Setzt eine Farbe auf einem bestimmten Pixel in einer LED Matrize. + * Das Koordinaten System für eine oben links Anfangende Matrize ist wie folgt: + * ----> X + * | + * | + * | + * v + * Y + * Die Anordnung für alle ungeraden Spalten ist von unten nach oben (Zig-Zag) + * Die Pixel gehen von Index 0 bis Breite/Länge - 1 + */ + //%blockId="Matrix_setPixel" block="%matrix| setze Pixel x %x| y %y| auf Farbe %colour" //%weight=70 //%colour.shadow=neopixel_colors //% subcategory=Matrix //% group="Kontrolle" setPixel(x: number, y: number, colour: number): void { if (x < 0 || x > this.Width || y < 0 || y > this.Height) { + //If the pixel does not fit on screen, do not draw it return; - } //If the pixel does not fit on screen, do not draw it (to avoid aliasing) - if (!(x % 2)) { + } + if (x % 2 == 0) { + //Because of the zig-zag formation of the panel all even rows (including 0) are drawn top to bottom this.strip.setPixelColor(y + x * this.Height, colour); - } //Because of the zig-zag formation of the panel all even rows (including 0) are drawn top to bottom - else { - this.strip.setPixelColor(this.Height - y + x * this.Height, colour); - } //While all odd rows are drawn bottom to top + } else { + //While all odd rows are drawn bottom to top + this.strip.setPixelColor(this.Height - 1 - y + x * this.Height, colour); + } } /** * scroll text on the matrix @@ -806,7 +823,7 @@ namespace neopixel { * @param matrixWidth the amount of leds horizontally * @param matrixheight the amount of leds vertically */ - //%blockId="Matrix_Create" block="Matrix at pin %pin|with a width of %matrixWidth|height of %matrixheight" + //%blockId="Matrix_Create" block="matrix auf pin %pin|mit einer Breite von %matrixWidth|und Höhe von %matrixheight" //%weight=100 //% subcategory=Matrix //%parts="neopixel" From 4d0542d8f10bc486c5ef36b2015cf80e7684f161 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 13:12:20 +0100 Subject: [PATCH 149/253] fix position text --- neopixel.ts | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index abe56d7..6e9aa92 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -641,6 +641,7 @@ namespace neopixel { show(): void { this.strip.show(); } + //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-128) %setpoint" //%weight=80 //%setpoint.defl=32 @@ -690,14 +691,15 @@ namespace neopixel { this.strip.setPixelColor(this.Height - 1 - y + x * this.Height, colour); } } + /** - * scroll text on the matrix + * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift */ - //%blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (0 - 100) %speed| Farbe %colour" - //%weight=75 + //% blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (1 - 100): %speed| Farbe: %colour" + //% weight=75 //% subcategory=Matrix - //%colour.shadow=neopixel_colors - //%speed.min=0 speed.max=100 speed.defl=50 + //% colour.shadow=neopixel_colors + //% speed.min=1 speed.max=100 speed.defl=50 //% group="Features" scrollText(text: string, speed: number, colour: number): void { this.strip.clear(); @@ -709,10 +711,34 @@ namespace neopixel { this.drawBitmap(bitmap, Xpos + 6 * letter, 0, 6, 8, colour); } this.strip.show(); - basic.pause(2000 / speed); + basic.pause(1000 / speed); this.strip.clear(); } } + + /** + * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift + */ + //%blockId="Matrix_text" block="%matrix Text: %text| X-Offset: %x_offset|Y-Offset: %y_offset|Farbe: %colour" + //%weight=74 + //% subcategory=Matrix + //%colour.shadow=neopixel_colors + //% group="Features" + showText( + text: string, + x_offset: number, + y_offset: number, + colour: number + ): void { + this.strip.clear(); + for (let letter = 0; letter < text.length; letter++) { + //for loop to retrieve all the letters from te text + let bitmap = getLettermap(text.charAt(letter)); + this.drawBitmap(bitmap, x_offset + 6 * letter, y_offset, 6, 8, colour); + } + this.strip.show(); + } + //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" //%weight=70 //% subcategory=Matrix @@ -842,6 +868,7 @@ namespace neopixel { return matrix; } + //Take in a string-character and return a bitmap to draw on the display function getLettermap(char: string): number[] { let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; From ac0e6f00fdad6c9e99142d047c7219c189e60011 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 13:43:53 +0100 Subject: [PATCH 150/253] remove non implemented y offset draw bitmap --- neopixel.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 6e9aa92..b2488d7 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -64,7 +64,7 @@ enum HiwonderPins { */ //% weight=5 color=#2896ff icon="\uf110" //% block.loc.de="NeoPixel" -//groups=['Kontrolle', 'Features', 'Setup'] +//% groups=['Setup', 'Features', 'Kontrolle'] namespace neopixel { let leds_total = 0; /** @@ -695,7 +695,7 @@ namespace neopixel { /** * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift */ - //% blockId="Matrix_scrollText" block="%matrix Text: %text| Geschwindigkeit (1 - 100): %speed| Farbe: %colour" + //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (1 - 100): %speed|Farbe: %colour" //% weight=75 //% subcategory=Matrix //% colour.shadow=neopixel_colors @@ -719,22 +719,18 @@ namespace neopixel { /** * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift */ - //%blockId="Matrix_text" block="%matrix Text: %text| X-Offset: %x_offset|Y-Offset: %y_offset|Farbe: %colour" + //%blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Farbe: %colour" //%weight=74 //% subcategory=Matrix //%colour.shadow=neopixel_colors + // x_offset.defl=0 //% group="Features" - showText( - text: string, - x_offset: number, - y_offset: number, - colour: number - ): void { + showText(text: string, x_offset: number, colour: number): void { this.strip.clear(); for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text let bitmap = getLettermap(text.charAt(letter)); - this.drawBitmap(bitmap, x_offset + 6 * letter, y_offset, 6, 8, colour); + this.drawBitmap(bitmap, x_offset + 6 * letter, 0, 6, 8, colour); } this.strip.show(); } @@ -777,6 +773,7 @@ namespace neopixel { } } } + //%blockId="Matrix_drawBitmap2" block="%matrix zeichne bitmap %bitmap bei x %xoffset| y %yoffset| mit Breite %width| Höhe %height in der Farbe %colour" //%weight=70 //% subcategory=Matrix From ce28edf8225243284b2c5b3de5ce7dbd3d692289 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 14:07:12 +0100 Subject: [PATCH 151/253] enable y positioning of text --- neopixel.ts | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index b2488d7..224a186 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -719,18 +719,24 @@ namespace neopixel { /** * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift */ - //%blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Farbe: %colour" + //%blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Y-Offset %y_offset|Farbe: %colour" //%weight=74 //% subcategory=Matrix //%colour.shadow=neopixel_colors - // x_offset.defl=0 + //% x_offset.defl=0 + //% y_offset.defl=0 //% group="Features" - showText(text: string, x_offset: number, colour: number): void { + showText( + text: string, + x_offset: number, + y_offset: number, + colour: number + ): void { this.strip.clear(); for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text let bitmap = getLettermap(text.charAt(letter)); - this.drawBitmap(bitmap, x_offset + 6 * letter, 0, 6, 8, colour); + this.drawBitmap(bitmap, x_offset + 6 * letter, y_offset, 6, 8, colour); } this.strip.show(); } @@ -752,10 +758,14 @@ namespace neopixel { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top for (let Ypos = height; Ypos >= 0; Ypos--) { - if (bitmap[Ypos] & (0x80 >> bitmask)) { + if ( + bitmap[Ypos] & (0x80 >> bitmask) && + Ypos + y < this.Height && + y + Ypos >= 0 + ) { //draw the pixel when there is a "1" in the bitmap this.strip.setPixelColor( - (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + (x + bitmask) * this.Height + Ypos + y + (this.Height - 8) / 2, colour ); } @@ -763,9 +773,13 @@ namespace neopixel { } else { //else draw from top to bottom for (let Ypos = 0; Ypos < this.Height; Ypos++) { - if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { + if ( + bitmap[7 - Ypos] & (0x80 >> bitmask) && + Ypos + y < this.Height && + y + Ypos >= 0 + ) { this.strip.setPixelColor( - (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + (x + bitmask) * this.Height + Ypos + y + (this.Height - 8) / 2, colour ); } From 5c7269c6d2ca2015decb5d14c2c4284f18d4646f Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 14:36:54 +0100 Subject: [PATCH 152/253] bitmap centered --- neopixel.ts | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 224a186..beab04b 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -708,7 +708,7 @@ namespace neopixel { for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text let bitmap = getLettermap(text.charAt(letter)); - this.drawBitmap(bitmap, Xpos + 6 * letter, 0, 6, 8, colour); + this.drawBitmapVcentered(bitmap, Xpos + 6 * letter, 6, 8, colour); } this.strip.show(); basic.pause(1000 / speed); @@ -717,39 +717,35 @@ namespace neopixel { } /** - * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift + * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift. Der Text ist vertikal mittig-zentriert. */ - //%blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Y-Offset %y_offset|Farbe: %colour" - //%weight=74 + //% blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Farbe: %colour" + //% weight=74 //% subcategory=Matrix - //%colour.shadow=neopixel_colors - //% x_offset.defl=0 - //% y_offset.defl=0 + //% colour.shadow=neopixel_colors + //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 //% group="Features" - showText( - text: string, - x_offset: number, - y_offset: number, - colour: number - ): void { + showText(text: string, x_offset: number, colour: number): void { this.strip.clear(); for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text let bitmap = getLettermap(text.charAt(letter)); - this.drawBitmap(bitmap, x_offset + 6 * letter, y_offset, 6, 8, colour); + this.drawBitmapVcentered(bitmap, x_offset + 6 * letter, 6, 8, colour); } this.strip.show(); } + /** + * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. + */ //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" //%weight=70 //% subcategory=Matrix //%colour.shadow=neopixel_colors //% group="Features" - drawBitmap( + drawBitmapVcentered( bitmap: number[], x: number, - y: number, width: number, height: number, colour: number @@ -758,14 +754,10 @@ namespace neopixel { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top for (let Ypos = height; Ypos >= 0; Ypos--) { - if ( - bitmap[Ypos] & (0x80 >> bitmask) && - Ypos + y < this.Height && - y + Ypos >= 0 - ) { + if (bitmap[Ypos] & (0x80 >> bitmask)) { //draw the pixel when there is a "1" in the bitmap this.strip.setPixelColor( - (x + bitmask) * this.Height + Ypos + y + (this.Height - 8) / 2, + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour ); } @@ -773,13 +765,9 @@ namespace neopixel { } else { //else draw from top to bottom for (let Ypos = 0; Ypos < this.Height; Ypos++) { - if ( - bitmap[7 - Ypos] & (0x80 >> bitmask) && - Ypos + y < this.Height && - y + Ypos >= 0 - ) { + if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { this.strip.setPixelColor( - (x + bitmask) * this.Height + Ypos + y + (this.Height - 8) / 2, + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour ); } From 548c4b2fbb88ac41056e82bfcf42347b3ddefec4 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 14:44:41 +0100 Subject: [PATCH 153/253] remove mirrored variant of draw bitmap --- neopixel.ts | 67 +---------------------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index beab04b..2519b10 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -738,7 +738,7 @@ namespace neopixel { /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. */ - //%blockId="Matrix_drawBitmap" block="%matrix draw bitmap %bitmap at x %x y %y| with width %width height %height in colour %colour" + //%blockId="Matrix_drawBitmap" block="%matrix zeichne bitmap %bitmap bei x: %x|mit Breite %width|Höhe %height|Farbe %colour" //%weight=70 //% subcategory=Matrix //%colour.shadow=neopixel_colors @@ -775,71 +775,6 @@ namespace neopixel { } } } - - //%blockId="Matrix_drawBitmap2" block="%matrix zeichne bitmap %bitmap bei x %xoffset| y %yoffset| mit Breite %width| Höhe %height in der Farbe %colour" - //%weight=70 - //% subcategory=Matrix - //%colour.shadow=neopixel_colors - //% group="Features" - drawBitmap2( - bitmap: number[], - xoffset: number, - yoffset: number, - width: number, - height: number, - colour: number, - doMirror: boolean = false - ): void { - let mirrored = 0; - if (doMirror) { - mirrored = 1; - } - if (width % 2) { - //To properly enable mirror, width has to be even, so if uneven width gets added to by 1 - width++; - } - //Setting end value of k to equal the width of the image to shift the bitmask to the correct position. for drawing the x-axis - for (let k = 0; k < width; k++) { - //Due to the zig-zag pattern of the matrix every odd value on the matrix has to be drawn from bottom to top, and the others top to bottom. - if (!((xoffset + k + mirrored) % 2)) { - //Value of j to select the values in the array to draw on the y-axis - for (let j = 0; j < height; j++) { - //only draw a pixel when there is a '1' in the bitmap, without drawing a "black" pixel when there is a '0', allowing layering of bitmaps. - if ( - bitmap[j] & (0b1 << (width - k - 1)) && - j + yoffset < this.Height && - yoffset + j >= 0 - ) { - //Draw the actual pixel at the position determined by the k, j , xoffset and yoffset values. - this.strip.setPixelColor( - ((mirrored - 1) * -k + xoffset + (width - k - 1) * mirrored) * - this.Height + - j + - yoffset, - colour - ); - } - } - } - //Drawing the odd lines top to bottom. - else { - for (let j = 0; j < height; j++) { - if ( - bitmap[j] & (0b1 << (width - k - 1)) && - yoffset + j < this.Height && - yoffset + j >= 0 - ) { - this.strip.setPixelColor( - ((mirrored - 1) * -k + xoffset + (width - k - 1) * mirrored) * - this.Height + - (this.Height - j - yoffset - 1), - colour - ); - } - } - } - } - } } /** From 7f9f2f9ff46b054fca48c4082819578da026d71e Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 15:13:58 +0100 Subject: [PATCH 154/253] log bitmap table --- neopixel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/neopixel.ts b/neopixel.ts index 2519b10..f844641 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -750,6 +750,7 @@ namespace neopixel { height: number, colour: number ): void { + console.log("draw bitmap[]= " + bitmap); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top From 113fbf53dc050c66620c76629bb11aaa31e5ac66 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 15:18:12 +0100 Subject: [PATCH 155/253] stringify log output --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index f844641..be36c92 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -750,7 +750,7 @@ namespace neopixel { height: number, colour: number ): void { - console.log("draw bitmap[]= " + bitmap); + console.log("draw bitmap[]= " + JSON.stringify(bitmap)); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top From ad6c0c812e6cffd690d51a486f3fa301fe01ae43 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 15:59:15 +0100 Subject: [PATCH 156/253] use enum for matrix size; trying to reorder grouping --- neopixel.ts | 90 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index be36c92..b10a712 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -49,6 +49,20 @@ enum NeoPixelMode { RGB_RGB = 3, } +/** + * NeoPixel matrix size definiitons + */ +enum matrixSizes { + //% block="8x8" + small_8x8, + //% block="32x8" + medium_32x8, + //% block="64x8" + large_64_8, + //% block="16x16" + medium_16x16, +} + /** * Available pins on ports (connectors) */ @@ -629,6 +643,45 @@ namespace neopixel { Shortest, } + /** + * Erstelle ein neues Matrix Objekt + * @param pin Pin an welchem die Matrize angeschlossen ist + * @param size Dimension des Panels in Breite x Höhe + */ + //% blockId="Matrix_Create" block="matrix auf Pin %pin|mit einer Grösse von %size" + //% weight=100 + //% subcategory=Matrix + //% parts="neopixel" + //% blockSetVariable=matrix + //% group="Setup" + export function create_matrix(pin: HiwonderPins, size: matrixSizes): Matrix { + let matrix = new Matrix(); + let w, h; + switch (size) { + case matrixSizes.small_8x8: + w = 8; + h = 8; + break; + case matrixSizes.medium_32x8: + w = 32; + h = 8; + break; + case matrixSizes.large_64_8: + w = 64; + h = 8; + break; + case matrixSizes.medium_16x16: + w = 16; + h = 16; + break; + } + matrix.strip = neopixel.create(pin, h * w); + matrix.Width = w; + matrix.Height = h; + + return matrix; + } + export class Matrix { strip: neopixel.Strip; Width: number; @@ -737,11 +790,16 @@ namespace neopixel { /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. + * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. + * @param x Horizontales Offset + * @param width Breite des Characters + * @param height Höhe des Characters + * @param color Farbe in welcher der Character angezeigt werden soll */ - //%blockId="Matrix_drawBitmap" block="%matrix zeichne bitmap %bitmap bei x: %x|mit Breite %width|Höhe %height|Farbe %colour" - //%weight=70 + //% blockId="Matrix_drawBitmap" block="%matrix zeichne bitmap %bitmap bei x: %x|mit Breite %width|Höhe %height|Farbe %colour" + //% weight=70 //% subcategory=Matrix - //%colour.shadow=neopixel_colors + //% colour.shadow=neopixel_colors //% group="Features" drawBitmapVcentered( bitmap: number[], @@ -778,32 +836,6 @@ namespace neopixel { } } - /** - * Create a new matrix object - * @param pin the pin to which the matrix is connected - * @param matrixWidth the amount of leds horizontally - * @param matrixheight the amount of leds vertically - */ - //%blockId="Matrix_Create" block="matrix auf pin %pin|mit einer Breite von %matrixWidth|und Höhe von %matrixheight" - //%weight=100 - //% subcategory=Matrix - //%parts="neopixel" - //%matrixWidth.defl=32 matrixheight.defl=8 - //%blockSetVariable=matrix - //% group="Setup" - export function create_matrix( - pin: HiwonderPins, - matrixWidth: number, - matrixHeight: number - ): Matrix { - let matrix = new Matrix(); - matrix.strip = neopixel.create(pin, matrixHeight * matrixWidth); - matrix.Width = matrixWidth; - matrix.Height = matrixHeight; - - return matrix; - } - //Take in a string-character and return a bitmap to draw on the display function getLettermap(char: string): number[] { let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; From ec984c94409a50085ac726b1ae464c3e8ab74d7c Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 21 Mar 2023 16:03:10 +0100 Subject: [PATCH 157/253] force Setup group to be on top in GUI --- neopixel.ts | 99 +++++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index b10a712..7d64414 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -81,6 +81,56 @@ enum HiwonderPins { //% groups=['Setup', 'Features', 'Kontrolle'] namespace neopixel { let leds_total = 0; + + /** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected on the Hiwonder board + * @param numleds number of leds in the strip, eg: 24,30,60,64 + */ + //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" + //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln" + //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." + //% weight=90 + //% parts="neopixel" + //% subcategory=Stripe + // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled + // trackArgs=0, 2 + //% blockSetVariable=strip + //% group="Setup" + export function create(pin: HiwonderPins, numleds: number): Strip { + leds_total += numleds; + let strip = new Strip(); + const mode = NeoPixelMode.RGB_GRB; + let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB_GRB; + strip.setBrightness(128); + // TODO: How can we solve this more elegant? When trying to cast, + // we can't use string literals here and can't change DigitalPin to non constant enum + let p; + switch (pin) { + case HiwonderPins.P1: + p = DigitalPin.P1; + break; + case HiwonderPins.P2: + p = DigitalPin.P2; + break; + case HiwonderPins.P13: + p = DigitalPin.P13; + break; + case HiwonderPins.P14: + p = DigitalPin.P14; + break; + case HiwonderPins.P16: + p = DigitalPin.P16; + break; + } + strip.setPin(p); + return strip; + } + /** * A NeoPixel strip */ @@ -476,55 +526,6 @@ namespace neopixel { return br; } - /** - * Create a new NeoPixel driver for `numleds` LEDs. - * @param pin the pin where the neopixel is connected on the Hiwonder board - * @param numleds number of leds in the strip, eg: 24,30,60,64 - */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" - //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln" - //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." - //% weight=90 - //% parts="neopixel" - //% subcategory=Stripe - // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled - // trackArgs=0, 2 - //% blockSetVariable=strip - //% group="Setup" - export function create(pin: HiwonderPins, numleds: number): Strip { - leds_total += numleds; - let strip = new Strip(); - const mode = NeoPixelMode.RGB_GRB; - let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; - strip.buf = pins.createBuffer(numleds * stride); - strip.start = 0; - strip._length = numleds; - strip._mode = mode || NeoPixelMode.RGB_GRB; - strip.setBrightness(128); - // TODO: How can we solve this more elegant? When trying to cast, - // we can't use string literals here and can't change DigitalPin to non constant enum - let p; - switch (pin) { - case HiwonderPins.P1: - p = DigitalPin.P1; - break; - case HiwonderPins.P2: - p = DigitalPin.P2; - break; - case HiwonderPins.P13: - p = DigitalPin.P13; - break; - case HiwonderPins.P14: - p = DigitalPin.P14; - break; - case HiwonderPins.P16: - p = DigitalPin.P16; - break; - } - strip.setPin(p); - return strip; - } - /** * creates a color from rgb numbers * @param r red channel From f7b8e8d4330f44c1300fc16d0c90c69b557b760e Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 12:03:03 +0100 Subject: [PATCH 158/253] Don't clear and auto show non scrolling text --- neopixel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 7d64414..f9d8ace 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -747,7 +747,8 @@ namespace neopixel { } /** - * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift + * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift. + * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden */ //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (1 - 100): %speed|Farbe: %colour" //% weight=75 @@ -772,6 +773,7 @@ namespace neopixel { /** * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift. Der Text ist vertikal mittig-zentriert. + * Es muss anschliessend ``anzeigen`` aufgerufen werden. */ //% blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Farbe: %colour" //% weight=74 @@ -780,13 +782,11 @@ namespace neopixel { //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 //% group="Features" showText(text: string, x_offset: number, colour: number): void { - this.strip.clear(); for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text let bitmap = getLettermap(text.charAt(letter)); this.drawBitmapVcentered(bitmap, x_offset + 6 * letter, 6, 8, colour); } - this.strip.show(); } /** From 703541d70bc5c4c59759c47d4c8b6201ba3471d2 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 13:34:14 +0100 Subject: [PATCH 159/253] more verbose log drawbitmap --- neopixel.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index f9d8ace..ac9072c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -810,6 +810,10 @@ namespace neopixel { colour: number ): void { console.log("draw bitmap[]= " + JSON.stringify(bitmap)); + console.log( + "x = " + x, + +" width = " + width + " height = " + height + " colour = " + colour + ); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top From 93a71d8c9160cf423d392cdc8da109507bc5c3cb Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 13:36:17 +0100 Subject: [PATCH 160/253] typo --- neopixel.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index ac9072c..f9e7e62 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -810,9 +810,7 @@ namespace neopixel { colour: number ): void { console.log("draw bitmap[]= " + JSON.stringify(bitmap)); - console.log( - "x = " + x, - +" width = " + width + " height = " + height + " colour = " + colour + console.log("x = " + x + " width = " + width + " height = " + height + " colour = " + colour ); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { From c77e5dde2eafb978cbd6f5ca4346ed942a0ceb94 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 13:49:17 +0100 Subject: [PATCH 161/253] log buffer before sending --- neopixel.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index f9e7e62..ada1a78 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,6 +296,7 @@ namespace neopixel { show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); + console.log("buffer to display= " + this.buf); ws2812b.sendBuffer(this.buf, this.pin); console.log("Estimated current for neopixels = " + this.power()); } @@ -810,7 +811,15 @@ namespace neopixel { colour: number ): void { console.log("draw bitmap[]= " + JSON.stringify(bitmap)); - console.log("x = " + x + " width = " + width + " height = " + height + " colour = " + colour + console.log( + "x = " + + x + + " width = " + + width + + " height = " + + height + + " colour = " + + colour ); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { From 06d2193db692600764dcc268fc8e8c08ec131d7e Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 13:57:35 +0100 Subject: [PATCH 162/253] stringified log --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index ada1a78..ecd0e0c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,7 +296,7 @@ namespace neopixel { show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); - console.log("buffer to display= " + this.buf); + console.log("buffer to display= " + JSON.stringify(this.buf)); ws2812b.sendBuffer(this.buf, this.pin); console.log("Estimated current for neopixels = " + this.power()); } From 55a01730bc79f609f9d4b9e5e3e66ca2ed0fdd5e Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 14:17:01 +0100 Subject: [PATCH 163/253] remove some logs, add when pixel drawn --- neopixel.ts | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index ecd0e0c..6881f1c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,7 +296,6 @@ namespace neopixel { show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); - console.log("buffer to display= " + JSON.stringify(this.buf)); ws2812b.sendBuffer(this.buf, this.pin); console.log("Estimated current for neopixels = " + this.power()); } @@ -522,9 +521,7 @@ namespace neopixel { function total_brightness_limit(): number { // a WS2812B LED has a current of about 60mA at full brightness with white color // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. - const br = Math.idiv(700 * 255, leds_total * 60) & 0xff; - console.log("Max brightness: " + br); - return br; + return Math.idiv(700 * 255, leds_total * 60) & 0xff; } /** @@ -811,22 +808,13 @@ namespace neopixel { colour: number ): void { console.log("draw bitmap[]= " + JSON.stringify(bitmap)); - console.log( - "x = " + - x + - " width = " + - width + - " height = " + - height + - " colour = " + - colour - ); for (let bitmask = 0; bitmask < width; bitmask++) { if (!((x + bitmask) % 2)) { //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top for (let Ypos = height; Ypos >= 0; Ypos--) { if (bitmap[Ypos] & (0x80 >> bitmask)) { //draw the pixel when there is a "1" in the bitmap + console.log("draw pixel at " + Ypos + " x = " + bitmask); this.strip.setPixelColor( (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour From a65dca51384b910f7b8f195be31387aba82a57a9 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 14:44:10 +0100 Subject: [PATCH 164/253] log pixel on even rows --- neopixel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 6881f1c..5050032 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -814,7 +814,7 @@ namespace neopixel { for (let Ypos = height; Ypos >= 0; Ypos--) { if (bitmap[Ypos] & (0x80 >> bitmask)) { //draw the pixel when there is a "1" in the bitmap - console.log("draw pixel at " + Ypos + " x = " + bitmask); + console.log("draw pixel at Y =" + Ypos + " X = " + bitmask); this.strip.setPixelColor( (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour @@ -825,6 +825,7 @@ namespace neopixel { //else draw from top to bottom for (let Ypos = 0; Ypos < this.Height; Ypos++) { if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { + console.log("draw pixel at Y =" + Ypos + " X = " + bitmask); this.strip.setPixelColor( (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour From 2ac3c2e6736ec948fdf5652de7c8e89861808684 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 17:09:59 +0100 Subject: [PATCH 165/253] update ws2812b lib --- neopixel.ts | 2 -- pxt.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 5050032..08a0650 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -814,7 +814,6 @@ namespace neopixel { for (let Ypos = height; Ypos >= 0; Ypos--) { if (bitmap[Ypos] & (0x80 >> bitmask)) { //draw the pixel when there is a "1" in the bitmap - console.log("draw pixel at Y =" + Ypos + " X = " + bitmask); this.strip.setPixelColor( (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour @@ -825,7 +824,6 @@ namespace neopixel { //else draw from top to bottom for (let Ypos = 0; Ypos < this.Height; Ypos++) { if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { - console.log("draw pixel at Y =" + Ypos + " X = " + bitmask); this.strip.setPixelColor( (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, colour diff --git a/pxt.json b/pxt.json index 1d9ad0a..55a2674 100644 --- a/pxt.json +++ b/pxt.json @@ -5,7 +5,7 @@ "license": "MIT", "dependencies": { "core": "file:../core", - "ws2812b": "github:microsoft/pxt-ws2812b#v0.1.1" + "ws2812b": "github:microsoft/pxt-ws2812b#v0.1.2" }, "files": ["README.md", "StartbitV2.ts", "StartbitRGBLight.ts", "neopixel.ts"], "testFiles": ["test.ts", "neotest.ts"], From b5f88aacbeecfbccf295d48a834321a89f7024be Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 17:22:07 +0100 Subject: [PATCH 166/253] log buffer content before sending --- neopixel.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index 08a0650..a008a1b 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,6 +296,10 @@ namespace neopixel { show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); + console.log("send buffer to pin " + this.pin + " with content: "); + for (let i = 0; i <= 3 * 8 * 8; i++) { + console.log(this.buf[i]); + } ws2812b.sendBuffer(this.buf, this.pin); console.log("Estimated current for neopixels = " + this.power()); } From cbe71b73f7baa98feeb75a7706027baea382bb06 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 22 Mar 2023 18:08:36 +0100 Subject: [PATCH 167/253] added draw_pattern as is (not working, will freeze program) --- neopixel.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index a008a1b..aaa67fa 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -791,6 +791,32 @@ namespace neopixel { } } + /** + * Zeichne Muster für Anzeige auf LED Matrix. + * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. + * TODO: Debug this + * @param i string pattern to convert into an image object + */ + //% block="zeichne Muster (NON WORKING)" + //% imageLiteral=1 + //% imageLiteralColumns=8 + //% imageLiteralRows=8 + draw_pattern(i: string): number[] { + // this is not pretty but basically, i is an Image + let im = (i); + let arr: number[] = []; + let rowValue = 0; + for (let i = 0; i < im.height(); i++) { + rowValue = 0; + for (let j = im.width() - 1; j >= 0; j--) { + let bit: number = im.pixel(j, i) ? 1 : 0; + rowValue = rowValue | (bit << (im.width() - 1 - j)); + } + arr.push(rowValue); + } + return arr; + } + /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. From 1d0ab3f7f23b16fac9803dcb70080c36c6c67314 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 27 Mar 2023 11:52:54 +0200 Subject: [PATCH 168/253] move draw pattern into matrix group --- neopixel.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index aaa67fa..f75ac5c 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -801,6 +801,8 @@ namespace neopixel { //% imageLiteral=1 //% imageLiteralColumns=8 //% imageLiteralRows=8 + //% subcategory=Matrix + //% group="Features" draw_pattern(i: string): number[] { // this is not pretty but basically, i is an Image let im = (i); From b7471d786f543893e167beb92769374bfd22baef Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 27 Mar 2023 13:12:52 +0200 Subject: [PATCH 169/253] added blockId for draw_pattern --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index f75ac5c..92e9208 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -797,7 +797,7 @@ namespace neopixel { * TODO: Debug this * @param i string pattern to convert into an image object */ - //% block="zeichne Muster (NON WORKING)" + //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" //% imageLiteral=1 //% imageLiteralColumns=8 //% imageLiteralRows=8 From 206c8647d8f351b2b911c7042840ecc6aac4cb32 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 28 Mar 2023 08:13:25 +0200 Subject: [PATCH 170/253] servo debug log --- StartbitV2.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index ba70b96..4e208ce 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -315,6 +315,8 @@ namespace Informatiktheater { duration: number = 300 ) { let position = mapValue(angle, 0, 180, 500, 2500); + console.log("servo index= " + index); + console.log("duration" + duration); let buf = pins.createBuffer(10); buf[0] = 0x55; From 982ed96226fff02271481554a5874252fd7ced63 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 28 Mar 2023 08:31:52 +0200 Subject: [PATCH 171/253] start servo enum index at 1 --- StartbitV2.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 4e208ce..1478d0a 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -287,7 +287,7 @@ namespace Informatiktheater { export enum ServoIndex { //% block="S1" - S1, + S1 = 1, //% block="S2" S2, //% block="S3" @@ -316,7 +316,6 @@ namespace Informatiktheater { ) { let position = mapValue(angle, 0, 180, 500, 2500); console.log("servo index= " + index); - console.log("duration" + duration); let buf = pins.createBuffer(10); buf[0] = 0x55; From d3c3bfaea7765a62142dfd03d599f3e394c7680d Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 28 Mar 2023 08:41:05 +0200 Subject: [PATCH 172/253] correct default for line follower enum --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1478d0a..2696af7 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -772,7 +772,7 @@ namespace Informatiktheater { export enum startbit_LineFollowerSensors { //% block="S1" - S1, + S1 = 1, //% block="S2" S2, //% block="S3" From 5df3b405fd1373143d44e9dbc6c72f30c641f74f Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 13:48:27 +0200 Subject: [PATCH 173/253] =?UTF-8?q?rename=20l=C3=B6schen=20to=20ausschalte?= =?UTF-8?q?n;=20implicit=20call=20show=20for=20fix=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neopixel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 92e9208..ac95833 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -709,7 +709,7 @@ namespace neopixel { this.strip.setBrightness(setpoint); } - //%blockId="Matrix_clear" block="%matrix| löschen" + //%blockId="Matrix_clear" block="%matrix| ausschalten" //%weight=8 //% subcategory=Matrix //% group="Kontrolle" @@ -789,6 +789,7 @@ namespace neopixel { let bitmap = getLettermap(text.charAt(letter)); this.drawBitmapVcentered(bitmap, x_offset + 6 * letter, 6, 8, colour); } + this.strip.show(); } /** From fa5fa5ee3b96227ed571eafaf9aa1ec09f37fb39 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 14:22:03 +0200 Subject: [PATCH 174/253] commented out knob and line follower inits --- StartbitV2.ts | 78 +++++++++++++++++++++++++-------------------------- neopixel.ts | 5 ++++ 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 2696af7..bd021cd 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -82,20 +82,20 @@ namespace Informatiktheater { let lineFollowPin1: AnalogPin; let lineFollowPin2: AnalogPin; - //% weight=92 - //% blockId=lineFollowSensor_init - //% block="initialize line follower sensor|%port" - //% block.loc.de="initialisiere Linienfolger-Sensor|%port" - //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) - // Only P1 and P2 are analog inputs - export function lineFollowSensor_init(port: startbit_lineFollowPort) { - switch (port) { - case startbit_lineFollowPort.port1: - lineFollowPin1 = AnalogPin.P1; - lineFollowPin2 = AnalogPin.P2; - break; - } - } + // //% weight=92 + // //% blockId=lineFollowSensor_init + // //% block="initialize line follower sensor|%port" + // //% block.loc.de="initialisiere Linienfolger-Sensor|%port" + // //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) + // // Only P1 and P2 are analog inputs + // export function lineFollowSensor_init(port: startbit_lineFollowPort) { + // switch (port) { + // case startbit_lineFollowPort.port1: + // lineFollowPin1 = AnalogPin.P1; + // lineFollowPin2 = AnalogPin.P2; + // break; + // } + // } export enum startbit_PinIOStatus { //% block="Off" @@ -123,17 +123,17 @@ namespace Informatiktheater { } let knobPin: AnalogPin; - //% weight=99 - //% blockId=knobSensor_init - //% block="initialize rotating knob|%port" - //% block.loc.de="initialisiere Drehknopf|%port" - export function knobSensor_init(port: startbit_knobPort) { - switch (port) { - case startbit_knobPort.port1: - knobPin = AnalogPin.P1; - break; - } - } + // //% weight=99 + // //% blockId=knobSensor_init + // //% block="initialize rotating knob|%port" + // //% block.loc.de="initialisiere Drehknopf|%port" + // export function knobSensor_init(port: startbit_knobPort) { + // switch (port) { + // case startbit_knobPort.port1: + // knobPin = AnalogPin.P1; + // break; + // } + // } export enum startbit_iic { port3 = 0x03, @@ -141,20 +141,20 @@ namespace Informatiktheater { port6 = 0x06, } - //% weight=93 - //% blockId=lineFollow_iic_init - //% block="initialize line follower iic|%port" - //% block.loc.de="initialisiere Linienfolger iic|%port" - export function lineFollow_iic_init(port: startbit_iic) { - switch (port) { - case startbit_iic.port3: - break; - case startbit_iic.port4: - break; - case startbit_iic.port6: - break; - } - } + // //% weight=93 + // //% blockId=lineFollow_iic_init + // //% block="initialize line follower iic|%port" + // //% block.loc.de="initialisiere Linienfolger iic|%port" + // export function lineFollow_iic_init(port: startbit_iic) { + // switch (port) { + // case startbit_iic.port3: + // break; + // case startbit_iic.port4: + // break; + // case startbit_iic.port6: + // break; + // } + // } export function startbit_Init() { startbit_initRGBLight(); diff --git a/neopixel.ts b/neopixel.ts index ac95833..66df32a 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -709,7 +709,12 @@ namespace neopixel { this.strip.setBrightness(setpoint); } + /** + * Clear all LED's + * You have to call ``show`` afterwards + */ //%blockId="Matrix_clear" block="%matrix| ausschalten" + //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //%weight=8 //% subcategory=Matrix //% group="Kontrolle" From 9f43e80b2f0e327357e6dd81c15bfcbae8898ef1 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 14:32:54 +0200 Subject: [PATCH 175/253] remove line follower and knob because commented block still appear in makecode --- StartbitV2.ts | 108 -------------------------------------------------- 1 file changed, 108 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bd021cd..eb895a8 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -76,27 +76,6 @@ namespace Informatiktheater { } } - export enum startbit_lineFollowPort { - port1 = 0x01, - } - - let lineFollowPin1: AnalogPin; - let lineFollowPin2: AnalogPin; - // //% weight=92 - // //% blockId=lineFollowSensor_init - // //% block="initialize line follower sensor|%port" - // //% block.loc.de="initialisiere Linienfolger-Sensor|%port" - // //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) - // // Only P1 and P2 are analog inputs - // export function lineFollowSensor_init(port: startbit_lineFollowPort) { - // switch (port) { - // case startbit_lineFollowPort.port1: - // lineFollowPin1 = AnalogPin.P1; - // lineFollowPin2 = AnalogPin.P2; - // break; - // } - // } - export enum startbit_PinIOStatus { //% block="Off" //% block.loc.de="Aus" @@ -106,56 +85,6 @@ namespace Informatiktheater { Hight = 0x01, } - export enum startbit_LineFollowerSensor { - //% block="Sensor 1" - LFSensor_1 = 0x00, - //% block="Sensor 2" - LFSensor_2 = 0x01, - } - - export enum startbit_busServoPort { - //% block="Port 6" - port6 = 0x06, - } - - export enum startbit_knobPort { - port1 = 0x01, - } - - let knobPin: AnalogPin; - // //% weight=99 - // //% blockId=knobSensor_init - // //% block="initialize rotating knob|%port" - // //% block.loc.de="initialisiere Drehknopf|%port" - // export function knobSensor_init(port: startbit_knobPort) { - // switch (port) { - // case startbit_knobPort.port1: - // knobPin = AnalogPin.P1; - // break; - // } - // } - - export enum startbit_iic { - port3 = 0x03, - port4 = 0x04, - port6 = 0x06, - } - - // //% weight=93 - // //% blockId=lineFollow_iic_init - // //% block="initialize line follower iic|%port" - // //% block.loc.de="initialisiere Linienfolger iic|%port" - // export function lineFollow_iic_init(port: startbit_iic) { - // switch (port) { - // case startbit_iic.port3: - // break; - // case startbit_iic.port4: - // break; - // case startbit_iic.port6: - // break; - // } - // } - export function startbit_Init() { startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); @@ -589,29 +518,6 @@ namespace Informatiktheater { } } - //% weight=89 - //% blockId=startbit_lineSensorValue blockGap=50 - //% block="get line follower sensor|%sensor|ad value" - //% block.loc.de="Linienfolger |%sensor|ad Wert" - //% subcategory=Sensor - export function startbit_lineSensorValue( - sensor: startbit_LineFollowerSensor - ): number { - let s1 = 0; - let s2 = 0; - - s1 = pins.analogReadPin(lineFollowPin1); - s2 = pins.analogReadPin(lineFollowPin2); - s1 = (s1 * 255) / 1023; - s2 = (s2 * 255) / 1023; - - if (sensor == startbit_LineFollowerSensor.LFSensor_1) { - return 255 - s1; - } else { - return 255 - s2; - } - } - let distanceBak = 0; /** * Get the distance of ultrasonic detection to the obstacle @@ -642,20 +548,6 @@ namespace Informatiktheater { return Math.round((distance * 10) / 6 / 58 / 1.6); } - /** - * Get the ad value of the knob moudule - */ - //% weight=92 - //% blockId=startbit_getKnobValue - //% block="get rotating knob|value (0~255)" - //% block.loc.de="Drehknopf|Wert (0~255)" - //% subcategory=Sensor - export function startbit_getKnobValue(): number { - let adValue = pins.analogReadPin(knobPin); - adValue = (adValue * 255) / 1023; - return adValue; - } - /** * Initialize RGB */ From e5ced5e51aaa349d79682c6a6d6d06af994363c1 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 14:38:46 +0200 Subject: [PATCH 176/253] remove knob and linefollwer in sensor cat --- StartbitV2.ts | 95 --------------------------------------------------- 1 file changed, 95 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index eb895a8..fdaa767 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -490,34 +490,6 @@ namespace Informatiktheater { return val; } - //% weight=96 - //% blockId=startbit_readLineFollowerStatus - //% block="Line follower status $status" - //% block.loc.de="Linienfolger $status ?" - //% subcategory=Sensor - export function startbit_readLineFollowerStatus( - status: startbit_lineFollower - ): boolean { - let s1 = 0; - let s2 = 0; - - s1 = pins.analogReadPin(lineFollowPin1); - s2 = pins.analogReadPin(lineFollowPin2); - s1 = (s1 * 255) / 1023; - s2 = (s2 * 255) / 1023; - if (s1 < 200) s1 = 0; - else s1 = 1; - if (s2 < 200) s2 = 0; - else s2 = 1; - - let s = ((1 & s1) << 1) | s2; - if (s == status) { - return true; - } else { - return false; - } - } - let distanceBak = 0; /** * Get the distance of ultrasonic detection to the obstacle @@ -682,74 +654,7 @@ namespace Informatiktheater { White, } - const LINE_FOLLOWER_I2C_ADDR = 0x78; - - //% weight=95 blockId=startbit_line_followers blockGap=50 - //% block="Line follower %lineFollowerSensor in %LineColor ?" - //% block.loc.de="Linienfolger %lineFollowerSensor auf %LineColor ?" - //% inlineInputMode=inline - //% subcategory=Sensor - export function startbit_line_followers( - lineFollowerSensor: startbit_LineFollowerSensors, - LineColor: startbit_LineColor - ): boolean { - pins.i2cWriteNumber(LINE_FOLLOWER_I2C_ADDR, 1, NumberFormat.UInt8BE); - let data = pins.i2cReadNumber(LINE_FOLLOWER_I2C_ADDR, NumberFormat.UInt8BE); - let status = false; - switch (lineFollowerSensor) { - case startbit_LineFollowerSensors.S1: - if (data & 0x01) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S2: - if (data & 0x02) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S3: - if (data & 0x04) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - - case startbit_LineFollowerSensors.S4: - if (data & 0x08) { - if (LineColor == startbit_LineColor.Black) { - status = true; - } - } else { - if (LineColor == startbit_LineColor.White) { - status = true; - } - } - break; - } - return status; - } - // Trittmatte - export enum startbit_trittmattePort { port1 = 0x01, port2 = 0x02, From 8543fdfefd6ae0bf477cbf2bd4cc159574235fca Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 14:43:41 +0200 Subject: [PATCH 177/253] rename Board-LED --- StartbitV2.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index fdaa767..c6f8a5f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -535,17 +535,17 @@ namespace Informatiktheater { } /** - * Set the brightness of the strip. This flag only applies to future operation. + * Set the brightness of the LED. This flag only applies to future operation. * @param brightness a measure of LED brightness in 0-255. eg: 255 */ //% blockId="startbit_setBrightness" //% block="set brightness value to %brightness" //% block.loc.de="setze Helligkeit auf Wert %brightness" //% brightness.min=0 brightness.max=255 brightness.defl=255 - //% jsdoc.loc.de="Setze die Hellighkeit des LED Streifens. Dies gilt nur zukünftige Operationen." + //% jsdoc.loc.de="Setze die Hellighkeit der LED. Dies gilt nur zukünftige Operationen." //% brightness.loc.de="LED Helligkeit zwischen 0 bis 255" //% weight=100 - //% subcategory=Onboard-LED + //% subcategory=Board-LED export function startbit_setBrightness(brightness: number): void { lhRGBLight.setBrightness(brightness); lhRGBLight.show(); @@ -554,7 +554,7 @@ namespace Informatiktheater { //% weight=99 blockId=startbit_setPixelRGBArgs //% block="set|%lightoffset|color to %rgb" //% block.loc.de="setze Farbe von|%lightoffset|auf %rgb" - //% subcategory=Onboard-LED + //% subcategory=Board-LED export function startbit_setPixelRGBArgs( lightoffset: StartbitLights, rgb: StartbitRGBColors @@ -567,7 +567,7 @@ namespace Informatiktheater { //% block="Light on" //% block.loc.de="Licht an" //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" - //% subcategory=Onboard-LED + //% subcategory=Board-LED export function startbit_showLight() { lhRGBLight.show(); } @@ -579,7 +579,7 @@ namespace Informatiktheater { //% block="Light off" //% block.loc.de="Licht aus" //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" - //% subcategory=Onboard-LED + //% subcategory=Board-LED export function startbit_clearLight() { lhRGBLight.clear(); } @@ -654,7 +654,6 @@ namespace Informatiktheater { White, } - // Trittmatte export enum startbit_trittmattePort { port1 = 0x01, port2 = 0x02, From 179db16f24eaa821f897eb7173d8bfaf9183d60a Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 14:46:40 +0200 Subject: [PATCH 178/253] rename LED all to LED 1 + 2 --- StartbitRGBLight.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitRGBLight.ts b/StartbitRGBLight.ts index ddb21e2..03f8892 100644 --- a/StartbitRGBLight.ts +++ b/StartbitRGBLight.ts @@ -33,14 +33,14 @@ enum StartbitRGBColors { } enum StartbitLights { - //% block="Light 1" + //% block="LED 1" //% block.loc.de="LED 1" Light1 = 0x00, - //% block="Light 2" + //% block="LED 2" //% block.loc.de="LED 2" Light2 = 0x01, - //% block="All" - //% block.loc.de="Alle" + //% block="LED 1 + 2" + //% block.loc.de="LED 1 + 2" All = 0x06, } From 5eddf8e5f600a0b5026558ab6c65f424cbba47f3 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 15:00:31 +0200 Subject: [PATCH 179/253] rainbow start end vals; rename block text --- neopixel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 66df32a..faa2bd3 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -171,6 +171,8 @@ namespace neopixel { //% jsdoc.loc.de="Zeigt ein Regenbogenmuster auf allen NeoPixeln an." //% strip.defl=strip //% startHue.shadow="colorWheelHsvPicker" + //% startHue.defl=1 + //% endHue.defl=255 //% endHue.shadow="colorWheelHsvPicker" //% weight=97 //% parts="neopixel" @@ -262,7 +264,7 @@ namespace neopixel { * @param rgb RGB color of the LED */ //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" - //% block.loc.de="%strip|setze Farbe(n) von %number NeoPixel(n) |an Position %pixeloffset|auf %rgb=neopixel_colors" + //% block.loc.de="%strip|setze Farbe von Neopixel %pixeloffset|auf %rgb=neopixel_colors|Anzahl %number" //% jsdoc.loc.de="Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip //% number.defl=1 @@ -782,7 +784,7 @@ namespace neopixel { * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift. Der Text ist vertikal mittig-zentriert. * Es muss anschliessend ``anzeigen`` aufgerufen werden. */ - //% blockId="Matrix_text" block="%matrix Text: %text|X-Offset: %x_offset|Farbe: %colour" + //% blockId="Matrix_text" block="%matrix Text: %text|Position: %x_offset|Farbe: %colour" //% weight=74 //% subcategory=Matrix //% colour.shadow=neopixel_colors From 57ae61f32ec8e00db60e271d22fd7e64cd9ceac9 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 15:02:54 +0200 Subject: [PATCH 180/253] remove dc motor block --- StartbitV2.ts | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c6f8a5f..8ccec2f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -261,29 +261,6 @@ namespace Informatiktheater { basic.pause(1); } - //% weight=96 - //% blockId=startbit_setMotorSpeed - //% block="set velocity for |motor 1 %speed1|and motor 2 %speed2" - //% block.loc.de="setze Geschwindigkeit für |Motor 1 %speed1|und Motor 2 %speed2" - //% speed1.min=-100 speed1.max=100 - //% speed2.min=-100 speed2.max=100 - //% subcategory=Servo/Motor - export function startbit_setMotorSpeed(speed1: number, speed2: number) { - if (speed1 > 100 || speed1 < -100 || speed2 > 100 || speed2 < -100) { - return; - } - speed1 = speed1 * -1; - speed2 = speed2 * -1; - let buf = pins.createBuffer(6); - buf[0] = 0x55; - buf[1] = 0x55; - buf[2] = 0x04; - buf[3] = 0x32; //cmd type - buf[4] = speed1; - buf[5] = speed2; - serial.writeBuffer(buf); - } - const APDS9960_I2C_ADDR = 0x39; const APDS9960_ID_1 = 0xa8; const APDS9960_ID_2 = 0x9c; From 901838817092800581ab9d5149c4d49270ddb560 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 15:06:55 +0200 Subject: [PATCH 181/253] pixel range english text corresponding to german --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index faa2bd3..3861019 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -263,7 +263,7 @@ namespace neopixel { * @param range how many pixels starting at position * @param rgb RGB color of the LED */ - //% blockId="neopixel_set_pixel_color" block="%strip|set %number pixel color(s)| at %pixeloffset|to %rgb=neopixel_colors" + //% blockId="neopixel_set_pixel_color" block="%strip|set color of Neopixel %pixeloffset|to %rgb=neopixel_colors|amount %number" //% block.loc.de="%strip|setze Farbe von Neopixel %pixeloffset|auf %rgb=neopixel_colors|Anzahl %number" //% jsdoc.loc.de="Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." //% strip.defl=strip From f992f0e5a3c19e822ffe39e4c30680ec1224be79 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 15:48:27 +0200 Subject: [PATCH 182/253] LED ein to LED einschalten --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 8ccec2f..51a12f8 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -542,7 +542,7 @@ namespace Informatiktheater { //% weight=97 blockId=startbit_showLight //% block="Light on" - //% block.loc.de="Licht an" + //% block.loc.de="Board-LED anzeigen" //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" //% subcategory=Board-LED export function startbit_showLight() { @@ -554,7 +554,7 @@ namespace Informatiktheater { */ //% weight=96 blockGap=50 blockId=startbit_clearLight //% block="Light off" - //% block.loc.de="Licht aus" + //% block.loc.de="Board-LED ausschalten" //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" //% subcategory=Board-LED export function startbit_clearLight() { From c2cb15359de0bc352fa859996966964223bd0590 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 18:16:23 +0200 Subject: [PATCH 183/253] option to for external battery_pack --- neopixel.ts | 65 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 3861019..6dd0e1b 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -73,6 +73,13 @@ enum HiwonderPins { P14 = DigitalPin.P14, P16 = DigitalPin.P16, } + +enum PowerSource { + //% block="intern" + Intern, + //% block="extern" + Extern, +} /** * Functions to operate NeoPixel strips. */ @@ -86,19 +93,25 @@ namespace neopixel { * Create a new NeoPixel driver for `numleds` LEDs. * @param pin the pin where the neopixel is connected on the Hiwonder board * @param numleds number of leds in the strip, eg: 24,30,60,64 + * @param power_source whether the board is powered from an external battery pack or with the onboard battery */ - //% blockId="neopixel_create" block="NeoPixel at pin %pin| with %numleds leds" - //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln" + //% blockId="neopixel_create" + //% block="NeoPixel at pin %pin| with %numleds leds| power source %power_source" + //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln| Spannungsquelle %power_source" //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." //% weight=90 //% parts="neopixel" + //% power_source.defl=PowerSource.Intern //% subcategory=Stripe // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled // trackArgs=0, 2 //% blockSetVariable=strip //% group="Setup" - export function create(pin: HiwonderPins, numleds: number): Strip { - leds_total += numleds; + export function create( + pin: HiwonderPins, + numleds: number, + power_source: PowerSource + ): Strip { let strip = new Strip(); const mode = NeoPixelMode.RGB_GRB; let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; @@ -107,6 +120,10 @@ namespace neopixel { strip._length = numleds; strip._mode = mode || NeoPixelMode.RGB_GRB; strip.setBrightness(128); + strip._power = power_source; + if (strip._power == PowerSource.Intern) { + leds_total += numleds; + } // TODO: How can we solve this more elegant? When trying to cast, // we can't use string literals here and can't change DigitalPin to non constant enum let p; @@ -142,6 +159,7 @@ namespace neopixel { start: number; // start offset in LED strip _length: number; // number of LEDs _mode: NeoPixelMode; + _power: PowerSource; /** * Shows all LEDs to a given color (range 0-255 for r, g, b). @@ -485,10 +503,15 @@ namespace neopixel { let green = unpackG(rgb); let blue = unpackB(rgb); - const br = - this.brightness < total_brightness_limit() - ? this.brightness - : total_brightness_limit(); + let br: number; + if (this._power == PowerSource.Intern) { + br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); + } else if (this._power == PowerSource.Extern) { + br = this.brightness; + } if (br < 255) { red = (red * br) >> 8; green = (green * br) >> 8; @@ -511,10 +534,15 @@ namespace neopixel { let green = unpackG(rgb); let blue = unpackB(rgb); - const br = - this.brightness < total_brightness_limit() - ? this.brightness - : total_brightness_limit(); + let br: number; + if (this._power == PowerSource.Intern) { + br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); + } else if (this._power == PowerSource.Extern) { + br = this.brightness; + } if (br < 255) { red = (red * br) >> 8; green = (green * br) >> 8; @@ -652,14 +680,21 @@ namespace neopixel { * Erstelle ein neues Matrix Objekt * @param pin Pin an welchem die Matrize angeschlossen ist * @param size Dimension des Panels in Breite x Höhe + * @param power_source Spannungsquelle welche die LED's versorgt (intern/extern) */ - //% blockId="Matrix_Create" block="matrix auf Pin %pin|mit einer Grösse von %size" + //% blockId="Matrix_Create" + //% block="matrix auf Pin %pin|mit einer Grösse von %size| Spannungsquelle %power_source" //% weight=100 + //% power_source.defl=PowerSource.Intern //% subcategory=Matrix //% parts="neopixel" //% blockSetVariable=matrix //% group="Setup" - export function create_matrix(pin: HiwonderPins, size: matrixSizes): Matrix { + export function create_matrix( + pin: HiwonderPins, + size: matrixSizes, + power_source: PowerSource + ): Matrix { let matrix = new Matrix(); let w, h; switch (size) { @@ -680,7 +715,7 @@ namespace neopixel { h = 16; break; } - matrix.strip = neopixel.create(pin, h * w); + matrix.strip = neopixel.create(pin, h * w, power_source); matrix.Width = w; matrix.Height = h; From 4d1e0e8c77f2d7d5c70eae044e95fd08fb1c4a31 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 29 Mar 2023 18:35:25 +0200 Subject: [PATCH 184/253] Board LED on/off english desrc --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 51a12f8..0b0c8d5 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -541,7 +541,7 @@ namespace Informatiktheater { } //% weight=97 blockId=startbit_showLight - //% block="Light on" + //% block="show board-LED" //% block.loc.de="Board-LED anzeigen" //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" //% subcategory=Board-LED @@ -553,7 +553,7 @@ namespace Informatiktheater { * Clear the color of the colored lights and turn off the lights. */ //% weight=96 blockGap=50 blockId=startbit_clearLight - //% block="Light off" + //% block="clear board-LED" //% block.loc.de="Board-LED ausschalten" //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" //% subcategory=Board-LED From d0e55795794799c5f094cc899a5cb61815f6274d Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:15:49 +0200 Subject: [PATCH 185/253] Update pxt.json name convention --- pxt.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pxt.json b/pxt.json index 55a2674..c986dbf 100644 --- a/pxt.json +++ b/pxt.json @@ -1,5 +1,5 @@ { - "name": "Informatiktheater", + "name": "informatiktheater", "version": "0.0.3", "description": "Blocks for Informatiktheater", "license": "MIT", From bd7953928b79c8d2cd41eb2a19c44514175f6bc0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:33:14 +0200 Subject: [PATCH 186/253] Update neopixel.ts Kompromiss doppelte Helligkeit mit interner Batterie. --- neopixel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 6dd0e1b..450e223 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -554,8 +554,8 @@ namespace neopixel { function total_brightness_limit(): number { // a WS2812B LED has a current of about 60mA at full brightness with white color - // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. - return Math.idiv(700 * 255, leds_total * 60) & 0xff; + // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. !!!exceptional double current!!!! + return Math.idiv(700 * 2 * 255, leds_total * 60) & 0xff; } /** From e35382089441cb115715a892bf47c18e1a7b92af Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:06:12 +0200 Subject: [PATCH 187/253] Update StartbitV2.ts --- StartbitV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 0b0c8d5..bd85c6e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,11 +1,11 @@ // Auto init hiwonder board when extension is added -Informatiktheater.startbit_Init(); +informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff -namespace Informatiktheater { +//% weight=10 color=#2896ff +namespace informatiktheater { export enum startbit_Colors { //% block="Red" //% block.loc.de="Rot" From 90f0dbf2dad69d551c4efc0ebdcb6060df67d15b Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:07:51 +0200 Subject: [PATCH 188/253] Update StartbitV2.ts icon --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bd85c6e..78a8ae0 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,7 +4,7 @@ informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff +//% weight=10 color=#2896ff icon="\uf630" namespace informatiktheater { export enum startbit_Colors { //% block="Red" From 21d99f0d0ba9395ee72bc4c541fa860f44146952 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:09:18 +0200 Subject: [PATCH 189/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 78a8ae0..cfc4334 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,7 +4,7 @@ informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff icon="\uf630" +//% weight=10 color=#2896ff icon="\f630" namespace informatiktheater { export enum startbit_Colors { //% block="Red" From 2781babc23853c168636fdac2115ab65ca58b578 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:13:51 +0200 Subject: [PATCH 190/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index cfc4334..bd85c6e 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,7 +4,7 @@ informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff icon="\f630" +//% weight=10 color=#2896ff namespace informatiktheater { export enum startbit_Colors { //% block="Red" From 0c44f27951e30bc493caa55a2aa33d0f4d05aac4 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 24 Apr 2023 13:45:01 +0200 Subject: [PATCH 191/253] debug log color val --- neopixel.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index 450e223..fb22ba2 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -293,6 +293,7 @@ namespace neopixel { //% subcategory=Stripe //% group="Kontrolle" setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + console.log("strip: show color : " + rgb); for (let i = 0; i < number; i++) { this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); } @@ -777,6 +778,7 @@ namespace neopixel { //% subcategory=Matrix //% group="Kontrolle" setPixel(x: number, y: number, colour: number): void { + console.log("matrix: show color : " + colour); if (x < 0 || x > this.Width || y < 0 || y > this.Height) { //If the pixel does not fit on screen, do not draw it return; From 64c549a3a25a0362df6428c3cbcfdfdc1228f397 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 24 Apr 2023 13:52:23 +0200 Subject: [PATCH 192/253] neopixel_color shadow --- neopixel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/neopixel.ts b/neopixel.ts index fb22ba2..7b7df94 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -289,6 +289,7 @@ namespace neopixel { //% number.min=1 //% number.min=255 //% weight=80 + //% rgb.shadow=neopixel_colors //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" From 69435b0753183759c0a95b37f5084344d7cb9f5f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 24 Apr 2023 13:57:08 +0200 Subject: [PATCH 193/253] strip pixel range defaults --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 7b7df94..688ccd7 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -287,7 +287,7 @@ namespace neopixel { //% strip.defl=strip //% number.defl=1 //% number.min=1 - //% number.min=255 + //% number.max=255 //% weight=80 //% rgb.shadow=neopixel_colors //% parts="neopixel" From 9d7d4099c18054caceb6ba31fee1195a80c438f0 Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 24 Apr 2023 14:13:03 +0200 Subject: [PATCH 194/253] pixel offset defaults --- neopixel.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index 688ccd7..81b11c4 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -288,6 +288,9 @@ namespace neopixel { //% number.defl=1 //% number.min=1 //% number.max=255 + //% pixeloffset.defl=0 + //% pixeloffset.min=0 + //% pixeloffset.max=255 //% weight=80 //% rgb.shadow=neopixel_colors //% parts="neopixel" From c4ad618b27418ab20f05348dd613f80d514ef49f Mon Sep 17 00:00:00 2001 From: sja Date: Mon, 24 Apr 2023 14:17:13 +0200 Subject: [PATCH 195/253] exchange func args positions --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 81b11c4..54ac372 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -296,7 +296,7 @@ namespace neopixel { //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" - setPixelColorRange(number: number, pixeloffset: number, rgb: number): void { + setPixelColorRange(pixeloffset: number, rgb: number, number: number): void { console.log("strip: show color : " + rgb); for (let i = 0; i < number; i++) { this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); From e13b4d08967b1be5e3e14fd6c54d3331743c8206 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 10:57:42 +0200 Subject: [PATCH 196/253] renamed mp3-box to soundbox --- StartbitV2.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bd85c6e..a2abc21 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,7 +4,7 @@ informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff +//% weight=10 color=#2896ff namespace informatiktheater { export enum startbit_Colors { //% block="Red" @@ -757,7 +757,7 @@ namespace informatiktheater { //% block="setze $this auf $list " //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3-Box + //% subcategory=Soundbox public createSongListArray(list: number[]) { this.list = list; this.TrackIndex = 0; @@ -768,7 +768,7 @@ namespace informatiktheater { //% block.loc.de="nächste Songnummer in Liste $this" //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3-Box + //% subcategory=Soundbox public playNextTrack() { if (this.TrackIndex < this.list.length) { this.TrackIndex += 1; @@ -782,7 +782,7 @@ namespace informatiktheater { //% block.loc.de="vorherige Songnummer in Liste $this" //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3-Box + //% subcategory=Soundbox public playPreviousTrack() { if (this.TrackIndex <= 0) { this.TrackIndex == 0; @@ -796,7 +796,7 @@ namespace informatiktheater { //% block.loc.de="Aktuelle Songnummer in liste %this" //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3-Box + //% subcategory=Soundbox public currentTrack(): number { return this.list[this.TrackIndex]; } @@ -806,7 +806,7 @@ namespace informatiktheater { //% block.loc.de="zurück zur ersten Songnummer in Liste %this" //% this.defl=Songliste //% this.shadow=variables_get - //% subcategory=MP3-Box + //% subcategory=Soundbox public gotoFirstTrack() { this.TrackIndex = 0; } @@ -820,7 +820,7 @@ namespace informatiktheater { //% block.loc.de="erstelle Songliste" //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." //% blockSetVariable=Songliste - //% subcategory=MP3-Box + //% subcategory=Soundbox export function createSongList(): SongList { return new SongList(); } From 49c31f11de751f753b44f3d1f2ccc0f1ebdddf78 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 11:13:28 +0200 Subject: [PATCH 197/253] remove some logs; extend to 16x16px --- neopixel.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 54ac372..3f67e35 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -297,7 +297,6 @@ namespace neopixel { //% subcategory=Stripe //% group="Kontrolle" setPixelColorRange(pixeloffset: number, rgb: number, number: number): void { - console.log("strip: show color : " + rgb); for (let i = 0; i < number; i++) { this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); } @@ -321,10 +320,6 @@ namespace neopixel { show() { // only supported in beta // ws2812b.setBufferMode(this.pin, this._mode); - console.log("send buffer to pin " + this.pin + " with content: "); - for (let i = 0; i <= 3 * 8 * 8; i++) { - console.log(this.buf[i]); - } ws2812b.sendBuffer(this.buf, this.pin); console.log("Estimated current for neopixels = " + this.power()); } @@ -848,8 +843,8 @@ namespace neopixel { */ //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" //% imageLiteral=1 - //% imageLiteralColumns=8 - //% imageLiteralRows=8 + //% imageLiteralColumns=16 + //% imageLiteralRows=16 //% subcategory=Matrix //% group="Features" draw_pattern(i: string): number[] { From bdab8b2a90b37dff5f8bab5b36aa26ecbad2a7d0 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 11:21:48 +0200 Subject: [PATCH 198/253] move draw_pattern outside matrix class --- neopixel.ts | 56 +++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 3f67e35..61d9750 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -835,33 +835,6 @@ namespace neopixel { this.strip.show(); } - /** - * Zeichne Muster für Anzeige auf LED Matrix. - * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. - * TODO: Debug this - * @param i string pattern to convert into an image object - */ - //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" - //% imageLiteral=1 - //% imageLiteralColumns=16 - //% imageLiteralRows=16 - //% subcategory=Matrix - //% group="Features" - draw_pattern(i: string): number[] { - // this is not pretty but basically, i is an Image - let im = (i); - let arr: number[] = []; - let rowValue = 0; - for (let i = 0; i < im.height(); i++) { - rowValue = 0; - for (let j = im.width() - 1; j >= 0; j--) { - let bit: number = im.pixel(j, i) ? 1 : 0; - rowValue = rowValue | (bit << (im.width() - 1 - j)); - } - arr.push(rowValue); - } - return arr; - } /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. @@ -923,6 +896,35 @@ namespace neopixel { } return letterMap; } + + + /** + * Zeichne Muster für Anzeige auf LED Matrix. + * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. + * TODO: Debug this + * @param i string pattern to convert into an image object + */ + //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" + //% imageLiteral=1 + //% imageLiteralColumns=16 + //% imageLiteralRows=16 + //% subcategory=Matrix + //% group="Features" + draw_pattern(i: string): number[] { + // this is not pretty but basically, i is an Image + let im = (i); + let arr: number[] = []; + let rowValue = 0; + for (let i = 0; i < im.height(); i++) { + rowValue = 0; + for (let j = im.width() - 1; j >= 0; j--) { + let bit: number = im.pixel(j, i) ? 1 : 0; + rowValue = rowValue | (bit << (im.width() - 1 - j)); + } + arr.push(rowValue); + } + return arr; + } } const font8x3 = hex` From 84d3d95538bad2775131fde7c4932cd1a9e26405 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 11:24:26 +0200 Subject: [PATCH 199/253] fnc added --- neopixel.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index 61d9750..13555bd 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -835,7 +835,6 @@ namespace neopixel { this.strip.show(); } - /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. @@ -897,7 +896,6 @@ namespace neopixel { return letterMap; } - /** * Zeichne Muster für Anzeige auf LED Matrix. * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. @@ -910,7 +908,7 @@ namespace neopixel { //% imageLiteralRows=16 //% subcategory=Matrix //% group="Features" - draw_pattern(i: string): number[] { + function draw_pattern(i: string): number[] { // this is not pretty but basically, i is an Image let im = (i); let arr: number[] = []; From 22d0616e7c29d998170d5ec9c795b39ad096967a Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 11:38:54 +0200 Subject: [PATCH 200/253] export fn --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 13555bd..ba9f432 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -908,7 +908,7 @@ namespace neopixel { //% imageLiteralRows=16 //% subcategory=Matrix //% group="Features" - function draw_pattern(i: string): number[] { + export function draw_pattern(i: string): number[] { // this is not pretty but basically, i is an Image let im = (i); let arr: number[] = []; From f8a42376450e1b70d3ad88445613581b33a1cff0 Mon Sep 17 00:00:00 2001 From: sja Date: Tue, 25 Apr 2023 15:49:00 +0200 Subject: [PATCH 201/253] remove double current for testing purposes --- neopixel.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index ba9f432..a304cb5 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -554,8 +554,9 @@ namespace neopixel { function total_brightness_limit(): number { // a WS2812B LED has a current of about 60mA at full brightness with white color - // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. !!!exceptional double current!!!! - return Math.idiv(700 * 2 * 255, leds_total * 60) & 0xff; + // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. + // NOTE sja: Removed !!!exceptional double current!!!! for testing the library on hardware. Having this enabled is not useful. Please set to "external" power supply if you don't want to have power limitation enabled. + return Math.idiv(700 * 255, leds_total * 60) & 0xff; } /** From 071bf98a4dd63cc7fabe7bc5c90788ed43865711 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 17:11:27 +0200 Subject: [PATCH 202/253] predefined icons --- neopixel.ts | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/neopixel.ts b/neopixel.ts index a304cb5..5d2a283 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -34,6 +34,108 @@ enum NeoPixelColors { Black = 0x000000, } +/** + * Named indexes for pre-defined icons below + */ +enum IconIndex { + //% block="Smiley hoch" + smiley_high, + //% block="Smiley biz hoch" + smiley_b_high, + //% block="Smiley Strich" + smiley_underscore, + //% block="Smiley biz runter" + smiley_b_down, + //% block="Smiley runter" + smiley_down, + //% block="Herz gross" + heart_big, + //% block="Herz mittel" + heart_medium, + //% block="Herz klein" + heart_small, + //% block="Totenkopf 1" + skull_1, + //% block="Totenkopf 2" + skull_2, + //% block="Pfeil rechts" + arrow_right, + //% block="Pfeil links" + arrow_left, + //% block="Sonne" + sun, + //% block="X" + X, + //% block="Tanz rechts" + dance_r, + //% block="Tanz mitte" + dance_c, + //% block="Tanz links" + dance_l, + //% block="Musiknote" + note, + //% block="Verboten" + forbidden, +} + +/** + * Array of arrays with pre-defined icons with a size of 16x16 pixels. + */ +const Icons: number[][] = [ + [0, 0, 0, 7224, 7224, 7224, 0, 384, 8580, 12300, 6168, 4080, 2016, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 6168, 4080, 2016, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 4080, 4080, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 2016, 4080, 4104, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 2016, 4080, 6168, 12300, 0], + [ + 0, 14364, 31806, 65151, 65535, 65535, 65535, 32766, 16380, 8184, 4080, 2016, + 960, 384, 0, 0, + ], + [0, 0, 0, 6168, 15420, 15996, 16380, 8184, 4080, 2016, 960, 384, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1056, 3696, 2016, 960, 384, 0, 0, 0, 0, 0, 0], + [ + 0, 2032, 2056, 4100, 8194, 8194, 8194, 9058, 4964, 2184, 5140, 3048, 1040, + 992, 0, 0, + ], + [ + 0, 256, 1984, 8176, 16376, 8176, 13208, 5008, 4064, 1728, 2976, 1088, 896, + 256, 0, 0, + ], + [0, 0, 0, 16, 24, 28, 32766, 32767, 32766, 32764, 24, 16, 0, 0, 0, 0], + [ + 0, 0, 0, 2048, 6144, 14336, 32767, 65535, 32767, 16383, 6144, 2048, 0, 0, 0, + 0, + ], + [ + 128, 128, 4228, 2056, 1488, 992, 2032, 30711, 2032, 992, 2512, 4104, 8324, + 128, 128, 0, + ], + [ + 32769, 16386, 8196, 4104, 2064, 1056, 576, 384, 384, 576, 1056, 2064, 4104, + 8196, 16386, 32769, + ], + [ + 1984, 448, 456, 264, 8184, 4480, 4480, 384, 768, 768, 768, 992, 544, 544, + 7712, 4144, + ], + [ + 1984, 896, 256, 256, 8184, 5000, 5000, 896, 256, 896, 896, 4064, 2080, 2080, + 2080, 6192, + ], + [ + 896, 768, 4864, 4352, 8160, 800, 800, 768, 384, 384, 1920, 1152, 1152, 1152, + 1216, 3136, + ], + [ + 0, 0, 0, 512, 768, 640, 576, 576, 576, 512, 512, 7680, 15872, 15872, 7168, + 0, + ], + [ + 4080, 12300, 24582, 20482, 34817, 33793, 33281, 33025, 32897, 32833, 32801, + 32785, 16394, 24582, 12300, 4080, + ], +]; + /** * Different modes for RGB or RGB+W NeoPixel strips */ @@ -836,6 +938,22 @@ namespace neopixel { this.strip.show(); } + /** + * Zeige vordefinierte Icons auf 16x16 grosser Matrixe an. + * Es muss anschliessend ``anzeigen`` aufgerufen werden. + */ + //% blockId="Matrix_icons" block="%matrix Icon: %icon|Farbe: %colour" + //% weight=76 + //% subcategory=Matrix + //% colour.shadow=neopixel_colors + //% group="Features" + draw_icon(icon: IconIndex, colour: number): void { + let icon_data = Icons[icon]; + console.log("Icon data to draw:" + icon_data); + this.drawBitmapVcentered(icon_data, 0, 16, 16, colour); + // this.strip.show(); + } + /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. From 5c5becdbb21fe08a45468a5e988f6d6d6a350b78 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 18:35:02 +0200 Subject: [PATCH 203/253] larger bitmask for 16x16 icons --- neopixel.ts | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 5d2a283..f0e5db5 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -950,12 +950,46 @@ namespace neopixel { draw_icon(icon: IconIndex, colour: number): void { let icon_data = Icons[icon]; console.log("Icon data to draw:" + icon_data); - this.drawBitmapVcentered(icon_data, 0, 16, 16, colour); + this.drawBitmapIcon16x16(icon_data, 16, 16, colour); // this.strip.show(); } + drawBitmapIcon16x16( + bitmap: number[], + width: number, + height: number, + colour: number + ): void { + console.log("draw bitmap[]= " + JSON.stringify(bitmap)); + for (let bitmask = 0; bitmask < width; bitmask++) { + if (!(bitmask % 2)) { + //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top + for (let Ypos = height; Ypos >= 0; Ypos--) { + if (bitmap[Ypos] & (0x8000 >> bitmask)) { + //draw the pixel when there is a "1" in the bitmap + this.strip.setPixelColor( + bitmask * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } else { + //else draw from top to bottom + for (let Ypos = 0; Ypos < this.Height; Ypos++) { + if (bitmap[7 - Ypos] & (0x8000 >> bitmask)) { + this.strip.setPixelColor( + bitmask * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } + } + } + /** * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. + * Dies funktioniert nur mit 8x8 grossen Zeichen (bitmasking) * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. * @param x Horizontales Offset * @param width Breite des Characters From b68745296508c79c567ca7a0129f5dbe0003d97f Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 18:47:10 +0200 Subject: [PATCH 204/253] bitmap lookup for 16x16 icons --- neopixel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index f0e5db5..d7a6840 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -968,7 +968,7 @@ namespace neopixel { if (bitmap[Ypos] & (0x8000 >> bitmask)) { //draw the pixel when there is a "1" in the bitmap this.strip.setPixelColor( - bitmask * this.Height + Ypos + (this.Height - 8) / 2, + bitmask * this.Height + Ypos + (this.Height - 16) / 2, colour ); } @@ -976,9 +976,9 @@ namespace neopixel { } else { //else draw from top to bottom for (let Ypos = 0; Ypos < this.Height; Ypos++) { - if (bitmap[7 - Ypos] & (0x8000 >> bitmask)) { + if (bitmap[15 - Ypos] & (0x8000 >> bitmask)) { this.strip.setPixelColor( - bitmask * this.Height + Ypos + (this.Height - 8) / 2, + bitmask * this.Height + Ypos + (this.Height - 16) / 2, colour ); } From 570ac7daa5f9e463c7488a5a24811105e15a53e9 Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 19:01:40 +0200 Subject: [PATCH 205/253] implicit call show for icons; don't show icon if size does not match --- neopixel.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index d7a6840..ace884f 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -940,7 +940,7 @@ namespace neopixel { /** * Zeige vordefinierte Icons auf 16x16 grosser Matrixe an. - * Es muss anschliessend ``anzeigen`` aufgerufen werden. + * Hat die Matrix eine andere Grösse, wird nichts angezeigt. */ //% blockId="Matrix_icons" block="%matrix Icon: %icon|Farbe: %colour" //% weight=76 @@ -948,10 +948,12 @@ namespace neopixel { //% colour.shadow=neopixel_colors //% group="Features" draw_icon(icon: IconIndex, colour: number): void { + if (this.Height != 16 || this.Width != 16) { + return; + } let icon_data = Icons[icon]; - console.log("Icon data to draw:" + icon_data); this.drawBitmapIcon16x16(icon_data, 16, 16, colour); - // this.strip.show(); + this.strip.show(); } drawBitmapIcon16x16( From 94e36b31e0de2ca25bb44d1093663c5f052a8ffd Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 19:04:22 +0200 Subject: [PATCH 206/253] don't show (non working) draw pattern block, hide draw array block --- neopixel.ts | 69 ++++++++++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/neopixel.ts b/neopixel.ts index ace884f..0a17cdc 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -989,20 +989,6 @@ namespace neopixel { } } - /** - * Zeige Bitmap auf Matrix. Der Text ist vertikal mittig-zentriert. - * Dies funktioniert nur mit 8x8 grossen Zeichen (bitmasking) - * @param bitmap Array mit bitmap. Jeder Eintrag entspricht einer Reihe im angezeigten Character. Nullposition ist oben rechts. - * @param x Horizontales Offset - * @param width Breite des Characters - * @param height Höhe des Characters - * @param color Farbe in welcher der Character angezeigt werden soll - */ - //% blockId="Matrix_drawBitmap" block="%matrix zeichne bitmap %bitmap bei x: %x|mit Breite %width|Höhe %height|Farbe %colour" - //% weight=70 - //% subcategory=Matrix - //% colour.shadow=neopixel_colors - //% group="Features" drawBitmapVcentered( bitmap: number[], x: number, @@ -1051,33 +1037,34 @@ namespace neopixel { return letterMap; } - /** - * Zeichne Muster für Anzeige auf LED Matrix. - * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. - * TODO: Debug this - * @param i string pattern to convert into an image object - */ - //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" - //% imageLiteral=1 - //% imageLiteralColumns=16 - //% imageLiteralRows=16 - //% subcategory=Matrix - //% group="Features" - export function draw_pattern(i: string): number[] { - // this is not pretty but basically, i is an Image - let im = (i); - let arr: number[] = []; - let rowValue = 0; - for (let i = 0; i < im.height(); i++) { - rowValue = 0; - for (let j = im.width() - 1; j >= 0; j--) { - let bit: number = im.pixel(j, i) ? 1 : 0; - rowValue = rowValue | (bit << (im.width() - 1 - j)); - } - arr.push(rowValue); - } - return arr; - } + // Uncomment when creating new icons + // /** + // * Zeichne Muster für Anzeige auf LED Matrix. + // * WICHTIG: Dieser Code läuft im Simulator, aber auf der Hardware werden nachfolgende Blöcke NICHT mehr ausgeführt. + // * TODO: Debug this + // * @param i string pattern to convert into an image object + // */ + // //% blockId="Matrix_freedraw" block="zeichne Muster (NON WORKING)" + // //% imageLiteral=1 + // //% imageLiteralColumns=16 + // //% imageLiteralRows=16 + // //% subcategory=Matrix + // //% group="Features" + // export function draw_pattern(i: string): number[] { + // // this is not pretty but basically, i is an Image + // let im = (i); + // let arr: number[] = []; + // let rowValue = 0; + // for (let i = 0; i < im.height(); i++) { + // rowValue = 0; + // for (let j = im.width() - 1; j >= 0; j--) { + // let bit: number = im.pixel(j, i) ? 1 : 0; + // rowValue = rowValue | (bit << (im.width() - 1 - j)); + // } + // arr.push(rowValue); + // } + // return arr; + // } } const font8x3 = hex` From df2a8b82971317000927a3aa42536bb03a7382eb Mon Sep 17 00:00:00 2001 From: sja Date: Wed, 3 May 2023 19:07:46 +0200 Subject: [PATCH 207/253] move ultrasonic init block to sensor; renamed sensor to ultraschall --- StartbitV2.ts | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index a2abc21..cf78547 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -56,26 +56,6 @@ namespace informatiktheater { port2 = 0x02, } - let echoPin: DigitalPin; - let trigPin: DigitalPin; - //% weight=91 - //% blockId=ultrasonic_init - //% block="initialize ultrasonic |%pin" - //% block.loc.de="initialisiere Ultraschall|%port" - //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) - export function ultrasonic_init(port: startbit_ultrasonicPort) { - switch (port) { - case startbit_ultrasonicPort.port1: - echoPin = DigitalPin.P2; - trigPin = DigitalPin.P1; - break; - case startbit_ultrasonicPort.port2: - echoPin = DigitalPin.P14; - trigPin = DigitalPin.P13; - break; - } - } - export enum startbit_PinIOStatus { //% block="Off" //% block.loc.de="Aus" @@ -467,6 +447,27 @@ namespace informatiktheater { return val; } + let echoPin: DigitalPin; + let trigPin: DigitalPin; + //% weight=1 + //% blockId=ultrasonic_init + //% block="initialize ultrasonic |%pin" + //% block.loc.de="initialisiere Ultraschall|%port" + //% subcategory=Ultraschall + //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) + export function ultrasonic_init(port: startbit_ultrasonicPort) { + switch (port) { + case startbit_ultrasonicPort.port1: + echoPin = DigitalPin.P2; + trigPin = DigitalPin.P1; + break; + case startbit_ultrasonicPort.port2: + echoPin = DigitalPin.P14; + trigPin = DigitalPin.P13; + break; + } + } + let distanceBak = 0; /** * Get the distance of ultrasonic detection to the obstacle @@ -475,7 +476,7 @@ namespace informatiktheater { //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" //% block.loc.de="Ultraschall|Distanz (cm)" - //% subcategory=Sensor + //% subcategory=Ultraschall export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); pins.setPull(trigPin, PinPullMode.PullNone); From e4f410a6579a034f32b989a37ae1bf944f9172f1 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 4 May 2023 18:45:04 +0200 Subject: [PATCH 208/253] Add files via upload --- icon.png | Bin 51183 -> 125440 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icon.png b/icon.png index dea3c8ef8840baa7a5627dda84298064bbb65ec3..42838a0a29fc1f0aedf08b187af1a83aed3d808d 100644 GIT binary patch literal 125440 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 N002ovPDHLkV1g=@v?Blj literal 51183 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 z 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 o Date: Sat, 20 May 2023 22:18:53 +0200 Subject: [PATCH 209/253] changeColour changed to 3a4cf7 dark blue --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index cf78547..3b73cb4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -4,7 +4,7 @@ informatiktheater.startbit_Init(); /* Informatiktheater package */ -//% weight=10 color=#2896ff +//% weight=10 color=#3a4cf7 namespace informatiktheater { export enum startbit_Colors { //% block="Red" From 1a1122d414e0771731fdb0e2a6aad6fd93ae224b Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 20 May 2023 22:31:40 +0200 Subject: [PATCH 210/253] colour dark 4 neopixel-Blocks --- neopixel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neopixel.ts b/neopixel.ts index 0a17cdc..1525296 100644 --- a/neopixel.ts +++ b/neopixel.ts @@ -185,7 +185,7 @@ enum PowerSource { /** * Functions to operate NeoPixel strips. */ -//% weight=5 color=#2896ff icon="\uf110" +//% weight=5 color=#3a4cf7 icon="\uf110" //% block.loc.de="NeoPixel" //% groups=['Setup', 'Features', 'Kontrolle'] namespace neopixel { From a141f8b35e42603b46102fb26932f2a0c4f83b56 Mon Sep 17 00:00:00 2001 From: Silvan Januth Date: Tue, 10 Oct 2023 12:05:30 +0200 Subject: [PATCH 211/253] new feautres from sandbox --- StartbitV2.ts | 1516 ++++++++++++++++++++++++++++++++++++++++++++----- pxt.json | 4 +- 2 files changed, 1377 insertions(+), 143 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 3b73cb4..a27f1a2 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1,72 +1,1310 @@ // Auto init hiwonder board when extension is added informatiktheater.startbit_Init(); +/** + * Well known colors for a NeoPixel strip + */ +enum NeoPixelColors { + //% block=red + //% block.loc.de="rot" + Red = 0xff0000, + //% block=orange + //% block.loc.de="orange" + Orange = 0xffa500, + //% block=yellow + //% block.loc.de="gelb" + Yellow = 0xffff00, + //% block=green + //% block.loc.de="grün" + Green = 0x00ff00, + //% block=blue + //% block.loc.de="blau" + Blue = 0x0000ff, + //% block=indigo + //% block.loc.de="indigo" + Indigo = 0x4b0082, + //% block=violet + //% block.loc.de="violett" + Violet = 0x8a2be2, + //% block=purple + //% block.loc.de="magenta" + Purple = 0xff00ff, + //% block=white + //% block.loc.de="weiss" + White = 0xffffff, + //% block=black + //% block.loc.de="schwarz" + Black = 0x000000, +} + + +/** + * DC motors on Hiwonder board + */ +enum HiwonderMotors { + + //% block="Motor 1" + M1, + //% block="Motor 2" + M2, + //% block="Motor 1 + 2" + M12 +} + +/** + * DC motors directions + */ +enum MotorDirections { + + //% block="Forward" + //% block.loc.de="Vorwärts" + Forward, + //% block="Backward" + //% block.loc.de="Rückwärts" + Backward +} + +/** + * Named indexes for pre-defined icons below + */ +enum IconIndex { + //% block="Smiley hoch" + smiley_high, + //% block="Smiley biz hoch" + smiley_b_high, + //% block="Smiley Strich" + smiley_underscore, + //% block="Smiley biz runter" + smiley_b_down, + //% block="Smiley runter" + smiley_down, + //% block="Herz gross" + heart_big, + //% block="Herz mittel" + heart_medium, + //% block="Herz klein" + heart_small, + //% block="Totenkopf 1" + skull_1, + //% block="Totenkopf 2" + skull_2, + //% block="Pfeil rechts" + arrow_right, + //% block="Pfeil links" + arrow_left, + //% block="Sonne" + sun, + //% block="X" + X, + //% block="Tanz rechts" + dance_r, + //% block="Tanz mitte" + dance_c, + //% block="Tanz links" + dance_l, + //% block="Musiknote" + note, + //% block="Verboten" + forbidden, +} + +/** + * Array of arrays with pre-defined icons with a size of 16x16 pixels. + */ +const Icons: number[][] = [ + [0, 0, 0, 7224, 7224, 7224, 0, 384, 8580, 12300, 6168, 4080, 2016, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 6168, 4080, 2016, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 4080, 4080, 0, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 2016, 4080, 4104, 0, 0], + [0, 0, 0, 7224, 7224, 7224, 0, 384, 384, 0, 0, 2016, 4080, 6168, 12300, 0], + [ + 0, 14364, 31806, 65151, 65535, 65535, 65535, 32766, 16380, 8184, 4080, 2016, + 960, 384, 0, 0, + ], + [0, 0, 0, 6168, 15420, 15996, 16380, 8184, 4080, 2016, 960, 384, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1056, 3696, 2016, 960, 384, 0, 0, 0, 0, 0, 0], + [ + 0, 2032, 2056, 4100, 8194, 8194, 8194, 9058, 4964, 2184, 5140, 3048, 1040, + 992, 0, 0, + ], + [ + 0, 256, 1984, 8176, 16376, 8176, 13208, 5008, 4064, 1728, 2976, 1088, 896, + 256, 0, 0, + ], + [0, 0, 0, 16, 24, 28, 32766, 32767, 32766, 32764, 24, 16, 0, 0, 0, 0], + [ + 0, 0, 0, 2048, 6144, 14336, 32767, 65535, 32767, 16383, 6144, 2048, 0, 0, 0, + 0, + ], + [ + 128, 128, 4228, 2056, 1488, 992, 2032, 30711, 2032, 992, 2512, 4104, 8324, + 128, 128, 0, + ], + [ + 32769, 16386, 8196, 4104, 2064, 1056, 576, 384, 384, 576, 1056, 2064, 4104, + 8196, 16386, 32769, + ], + [ + 1984, 448, 456, 264, 8184, 4480, 4480, 384, 768, 768, 768, 992, 544, 544, + 7712, 4144, + ], + [ + 1984, 896, 256, 256, 8184, 5000, 5000, 896, 256, 896, 896, 4064, 2080, 2080, + 2080, 6192, + ], + [ + 896, 768, 4864, 4352, 8160, 800, 800, 768, 384, 384, 1920, 1152, 1152, 1152, + 1216, 3136, + ], + [ + 0, 0, 0, 512, 768, 640, 576, 576, 576, 512, 512, 7680, 15872, 15872, 7168, + 0, + ], + [ + 4080, 12300, 24582, 20482, 34817, 33793, 33281, 33025, 32897, 32833, 32801, + 32785, 16394, 24582, 12300, 4080, + ], +]; + +/** + * Different modes for RGB or RGB+W NeoPixel strips + */ +enum NeoPixelMode { + //% block="RGB (GRB format)" + //% block.loc.de="GRB" + RGB_GRB = 1, + //% block="RGB+W" + //% block.loc.de="RGB+W" + RGBW = 2, + //% block="RGB (RGB format)" + //% block.loc.de="RGB" + RGB_RGB = 3, +} + +/** + * NeoPixel matrix size definiitons + */ +enum matrixSizes { + //% block="8x8" + small_8x8, + //% block="32x8" + medium_32x8, + //% block="64x8" + large_64_8, + //% block="16x16" + medium_16x16, +} + +/** + * Available pins on ports (connectors) + */ +enum HiwonderPins { + P1 = DigitalPin.P1, + P2 = DigitalPin.P2, + P13 = DigitalPin.P13, + P14 = DigitalPin.P14, + Onboard= DigitalPin.P15, + P16 = DigitalPin.P16, +} + +/** + * Available pins on ports (connectors) + */ +enum HiwonderMatrixPins { + P1 = DigitalPin.P1, + P2 = DigitalPin.P2, + P13 = DigitalPin.P13, + P14 = DigitalPin.P14, + P16 = DigitalPin.P16, +} + +enum PowerSource { + //% block="intern" + Intern, + //% block="extern" + Extern, +} + +const font8x3 = hex` + 0000000000000000 1038381010001000 6C6C480000000000 00287C28287C2800 + 2038403008701000 64640810204C4C00 2050502054483400 3030200000000000 + 1020202020201000 2010101010102000 0028387C38280000 0010107C10100000 + 0000000000303020 0000007C00000000 0000000000303000 0004081020400000 + 38444C5464443800 1030101010103800 3844041820407C00 3844043804443800 + 081828487C080800 7C40407804443800 1820407844443800 7C04081020202000 + 3844443844443800 3844443C04083000 0000303000303000 0000303000303020 + 0810204020100800 00007C00007C0000 2010080408102000 3844041810001000 + 38445C545C403800 384444447C444400 7844447844447800 3844404040443800 + 7844444444447800 7C40407840407C00 7C40407840404000 3844405C44443C00 + 4444447C44444400 3810101010103800 0404040444443800 4448506050484400 + 4040404040407C00 446C544444444400 4464544C44444400 3844444444443800 + 7844447840404000 3844444454483400 7844447848444400 3844403804443800 + 7C10101010101000 4444444444443800 4444444444281000 4444545454542800 + 4444281028444400 4444442810101000 7808102040407800 3820202020203800 + 0040201008040000 3808080808083800 1028440000000000 00000000000000FC + 3030100000000000 000038043C443C00 4040784444447800 0000384440443800 + 04043C4444443C00 0000384478403800 1820207820202000 00003C44443C0438 + 4040704848484800 1000101010101800 0800180808084830 4040485060504800 + 1010101010101800 0000685454444400 0000704848484800 0000384444443800 + 0000784444447840 00003C4444443C04 0000582420207000 0000384038043800 + 0020782020281000 0000484848582800 0000444444281000 00004444547C2800 + 0000484830484800 0000484848381060 0000780830407800 1820206020201800 + 1010100010101000 3008080C08083000 2850000000000000`; + /* Informatiktheater package */ //% weight=10 color=#3a4cf7 namespace informatiktheater { - export enum startbit_Colors { - //% block="Red" - //% block.loc.de="Rot" - Red = 0x01, - //% block="Green" - //% block.log.de="Grün" - Green = 0x02, - //% block="Blue" - //% block.loc.de="Blau" - Blue = 0x03, - //% block="Black" - //% block.loc.de="Schwarz" - Black = 0x04, - //% block="White" - //% block.loc.de="Weiss" - White = 0x05, - //% block="Empty" - //% block.loc.de="Leer" - None = 0x06, - } - - export enum startbit_lineFollower { - //% blockId="S1_OUT_S2_OUT" - //% block="Sensor1 and sensor2 beyond black line" - //% block.loc.de="Sensor1 und Sensor2 sind ausserhalb der schwarzen Linie" - S1_OUT_S2_OUT = 0x00, - //% blockId="S1_OUT_S2_IN - //% block="Sensor2 on black line but not sensor1" - //% block.loc.de="Sensor2 auf schwarzer Linie aber Sensor1 nicht" - S1_OUT_S2_IN = 0x01, - //% blockId="S1_IN_S2_OUT" - //% block="Sensor1 on black line but not sensor2" - //% block.loc.de="Sensor1 auf schwarzer Linie aber Sensor2 nicht" - S1_IN_S2_OUT = 0x02, - //% blockId="S1_IN_S2_IN" - //% block="Sensor1 and sensor2 on black line" - //% block.loc.de="Sensor1 und Sensor2 auf schwarzer Linie" - S1_IN_S2_IN = 0x03, - } - - export enum startbit_Servos { - Servo1 = 0x01, - Servo2 = 0x02, - } + + let leds_total = 0; + let motor_1_speed = 0; + let motor_2_speed = 0; + + + /** + * To be used as a shadow color picker block containing a custom array + */ + //% blockId=brightColorNumberPicker block="%value" + //% shim=TD_ID colorSecondary="#FFFFFF" + //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true + //% value.defl='#ff0000' weight=81 + //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' + //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' + //% group="colors" + export function __colorNumberPicker(value: number) { + return value; + } + + // Create a class to hold variable length lists of colors. This also helps to keep color lists + // from being used as function arguments to code blocks that shouldn't accept them + export class ColorPattern { + _colorList: Array; + + constructor(val: Array) { + this._colorList = val.slice(0); + } + + getColors(): Array { + return this._colorList; + } + } + + /** + * Create a new NeoPixel driver for `numleds` LEDs. + * @param pin the pin where the neopixel is connected on the Hiwonder board + * @param numleds number of leds in the strip, eg: 24,30,60,64 + * @param power_source whether the board is powered from an external battery pack or with the onboard battery + */ + //% blockId="neopixel_create" + //% block="NeoPixel at pin %pin| with %numleds leds| power source %power_source" + //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln| Spannungsquelle %power_source" + //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." + //% weight=90 + //% parts="neopixel" + //% power_source.defl=PowerSource.Intern + //% subcategory=Stripe + // TODO: How is trackArgs supposed to work? Without this, the simulator will work again, but without neopixel simulation enabled + // trackArgs=0, 2 + //% blockSetVariable=strip + //% group="Setup" + export function create( + pin: HiwonderPins, + numleds: number, + power_source: PowerSource + ): Strip { + let strip = new Strip(); + const mode = NeoPixelMode.RGB_GRB; + let stride = (mode as NeoPixelMode) === NeoPixelMode.RGBW ? 4 : 3; + strip.buf = pins.createBuffer(numleds * stride); + strip.start = 0; + strip._length = numleds; + strip._mode = mode || NeoPixelMode.RGB_GRB; + strip.setBrightness(128); + strip._power = power_source; + if (strip._power == PowerSource.Intern) { + leds_total += numleds; + } + // TODO: How can we solve this more elegant? When trying to cast, + // we can't use string literals here and can't change DigitalPin to non constant enum + let p; + switch (pin) { + case HiwonderPins.P1: + p = DigitalPin.P1; + break; + case HiwonderPins.P2: + p = DigitalPin.P2; + break; + case HiwonderPins.P13: + p = DigitalPin.P13; + break; + case HiwonderPins.P14: + p = DigitalPin.P14; + break; + case HiwonderPins.Onboard: + p = DigitalPin.P15; + break; + case HiwonderPins.P16: + p = DigitalPin.P16; + break; + } + strip.setPin(p); + return strip; + } + + + /** + * A NeoPixel strip + */ + export class Strip { + buf: Buffer; + pin: DigitalPin; + // TODO: encode as bytes instead of 32bit + brightness: number; + start: number; // start offset in LED strip + _length: number; // number of LEDs + _mode: NeoPixelMode; + _power: PowerSource; + + /** + * Shows all LEDs to a given color (range 0-255 for r, g, b). + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_strip_color" block="%strip|show color %rgb=neopixel_colors" + //% block.loc.de="%strip|zeige Farbe %rgb=neopixel_colors" + //% jsdoc.loc.de="Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf." + //% strip.defl=strip + //% weight=98 + //% parts="neopixel" + //% group="Kontrolle" + //% subcategory=Stripe + showColor(rgb: number) { + rgb = rgb >> 0; + this.setAllRGB(rgb); + this.show(); + } + + /** + * Shows a rainbow pattern on all LEDs. + * @param startHue the start hue value for the rainbow, e.g. 0 is red, 120 green, 240 blue, 360 red + * @param endHue the end hue value for the rainbow + */ + //% blockId="neopixel_set_strip_rainbow" block="%strip|show rainbow from %startHue|to %endHue" + //% block.loc.de="%strip|zeige Regenbogen von Farbton %startHue|bis %endHue" + //% jsdoc.loc.de="Zeigt ein Regenbogenmuster auf allen NeoPixeln an." + //% strip.defl=strip + //% startHue.shadow="colorWheelHsvPicker" + //% startHue.defl=1 + //% endHue.defl=255 + //% endHue.shadow="colorWheelHsvPicker" + //% weight=97 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Features" + showRainbow(startHue: number = 1, endHue: number = 255) { + if (this._length <= 0) return; + + startHue = (startHue * 360) / 255; + startHue = startHue >> 0; + endHue = (endHue * 360) / 255; + endHue = endHue >> 0; + + const saturation = 100; + const luminance = 50; + const steps = this._length; + const direction = HueInterpolationDirection.Clockwise; + // if (endHue > startHue) { + // direction = HueInterpolationDirection.Clockwise; + // } else if (endHue < startHue) { + // direction = HueInterpolationDirection.CounterClockwise; + // } + + //hue + const h1 = startHue; + const h2 = endHue; + let hDistCW; + let hDistCCW; + let hStepCW; + let hStepCCW; + + // In case we have a full rainbow + if (h2 !== h1 && (h2 + 360 - h1) % 360 == 0) { + hDistCW = 360; + hDistCCW = 360; + } else { + hDistCW = (h2 + 360 - h1) % 360; + hDistCCW = (h1 + 360 - h2) % 360; + } + hStepCW = Math.idiv(hDistCW * 100, steps); + hStepCCW = Math.idiv(-(hDistCCW * 100), steps); + let hStep: number; + + if (direction === HueInterpolationDirection.Clockwise) { + hStep = hStepCW; + } else if (direction === HueInterpolationDirection.CounterClockwise) { + hStep = hStepCCW; + } else { + hStep = hDistCW < hDistCCW ? hStepCW : hStepCCW; + } + + const h1_100 = h1 * 100; //we multiply by 100 so we keep more accurate results while doing interpolation + + //sat + const s1 = saturation; + const s2 = saturation; + const sDist = s2 - s1; + const sStep = Math.idiv(sDist, steps); + const s1_100 = s1 * 100; + + //lum + const l1 = luminance; + const l2 = luminance; + const lDist = l2 - l1; + const lStep = Math.idiv(lDist, steps); + const l1_100 = l1 * 100; + + //interpolate + if (steps === 1) { + this.setPixelColor(0, hsl(h1 + hStep, s1 + sStep, l1 + lStep)); + } else { + this.setPixelColor(0, hsl(startHue, saturation, luminance)); + for (let i = 1; i < steps - 1; i++) { + const h = Math.idiv(h1_100 + i * hStep, 100) + 360; + const s = Math.idiv(s1_100 + i * sStep, 100); + const l = Math.idiv(l1_100 + i * lStep, 100); + this.setPixelColor(i, hsl(h, s, l)); + } + this.setPixelColor(steps - 1, hsl(endHue, saturation, luminance)); + } + this.show(); + } + + /** + * Set LED to a given color (range 0-255 for r, g, b). + * You need to call ``show`` to make the changes visible. + * @param pixeloffset position of the NeoPixel in the strip + * @param range how many pixels starting at position + * @param rgb RGB color of the LED + */ + //% blockId="neopixel_set_pixel_color" block="%strip|set color of Neopixel %pixeloffset|to %rgb=neopixel_colors|amount %number" + //% block.loc.de="%strip|setze Farbe von Neopixel %pixeloffset|auf %rgb=neopixel_colors|Anzahl %number" + //% jsdoc.loc.de="Setzt die NeoPixel im Interval mit der angegebenen Startnummer auf die angegebene Farbe. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." + //% strip.defl=strip + //% number.defl=1 + //% number.min=1 + //% number.max=255 + //% pixeloffset.defl=0 + //% pixeloffset.min=0 + //% pixeloffset.max=255 + //% weight=80 + //% rgb.shadow=neopixel_colors + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + setPixelColorRange(pixeloffset: number, rgb: number, number: number): void { + for (let i = 0; i < number; i++) { + this.setPixelRGB((pixeloffset + i) >> 0, rgb >> 0); + } + } + + setPixelColor(pixeloffset: number, rgb: number): void { + this.setPixelRGB(pixeloffset >> 0, rgb >> 0); + } + + /** + * Send all the changes to the strip. + */ + //% blockId="neopixel_show" block="%strip|show" + //% block.loc.de="%strip|anzeigen" + //% jsdoc.loc.de="Sendet alle Änderungen an die NeoPixel." + //% strip.defl=strip + //% weight=10 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + show() { + // only supported in beta + // ws2812b.setBufferMode(this.pin, this._mode); + ws2812b.sendBuffer(this.buf, this.pin); + console.log("Estimated current for neopixels = " + this.power()); + } + + /** + * Turn off all LEDs. + * You need to call ``show`` to make the changes visible. + */ + //% blockId="neopixel_clear" block="%strip|clear" + //% block.loc.de="%strip|ausschalten" + //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." + //% strip.defl=strip + //% weight=9 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + clear(): void { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.fill(0, this.start * stride, this._length * stride); + } + + /** + * Gets the number of pixels declared on the strip + */ + //% blockId="neopixel_length" block="%strip|length" + //% block.loc.de="%strip|Länge" + //% jsdoc.loc.de="Die Anzahl der NeoPixel, die der Treiber verwaltet." + //% strip.defl=strip + //% weight=60 + //% subcategory=Stripe + //% group="Setup" + length() { + return this._length; + } + + /** + * Set the brightness of the strip. This flag only applies to future operation. + * The highest possible brightness level depends on the number of individual LED's set at ``create``. + * The brightness will be capped at this threshold. + * @param brightness a measure of LED brightness in 0-255. eg: 100 + */ + //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" + //% block.loc.de="%strip|setze Helligkeit %brightness" + //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." + //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% strip.defl=strip + //% weight=99 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + setBrightness(brightness: number): void { + this.brightness = brightness & 0xff; + } + + /** + * Shift LEDs forward and clear with zeros. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to shift forward, eg: 1 + */ + //% blockId="neopixel_shift" block="%strip|shift pixels by %offset" + //% block.loc.de="%strip|verschiebe NeoPixel um %offset" + //% jsdoc.loc.de="Verschiebt die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." + //% strip.defl=strip + //% weight=40 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + shift(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.shift( + -offset * stride, + this.start * stride, + this._length * stride + ); + } + + /** + * Rotate LEDs forward. + * You need to call ``show`` to make the changes visible. + * @param offset number of pixels to rotate forward, eg: 1 + */ + //% blockId="neopixel_rotate" block="%strip|rotate pixels by %offset" + //% block.loc.de="%strip|rotiere NeoPixel um %offset" + //% jsdoc.loc.de="Rotiert die Farben der NeoPixel. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." + //% strip.defl=strip + //% weight=39 + //% parts="neopixel" + //% subcategory=Stripe + //% group="Kontrolle" + rotate(offset: number = 1): void { + offset = offset >> 0; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + this.buf.rotate( + -offset * stride, + this.start * stride, + this._length * stride + ); + } + + setPin(pin: DigitalPin): void { + this.pin = pin; + pins.digitalWritePin(this.pin, 0); + // don't yield to avoid races on initialization + } + + /** + * Estimates the electrical current (mA) consumed by the current light configuration. + */ + power(): number { + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + const end = this.start + this._length; + let p = 0; + for (let i = this.start; i < end; ++i) { + for (let j = 0; j < stride; ++j) { + p += this.buf[i + j]; + } + } + return ( + Math.idiv(this.length() * 7, 10) /* 0.7mA per neopixel */ + + Math.idiv(p * 480, 10000) + ); /* rought approximation */ + } + + private setBufferRGB( + offset: number, + red: number, + green: number, + blue: number + ): void { + if (this._mode === NeoPixelMode.RGB_RGB) { + this.buf[offset + 0] = red; + this.buf[offset + 1] = green; + } else { + this.buf[offset + 0] = green; + this.buf[offset + 1] = red; + } + this.buf[offset + 2] = blue; + } + + private setAllRGB(rgb: number) { + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + let br: number; + if (this._power == PowerSource.Intern) { + br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); + } else if (this._power == PowerSource.Extern) { + br = this.brightness; + } + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + const end = this.start + this._length; + const stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + for (let i = this.start; i < end; ++i) { + this.setBufferRGB(i * stride, red, green, blue); + } + } + + setPixelRGB(pixeloffset: number, rgb: number): void { + if (pixeloffset < 0 || pixeloffset >= this._length) return; + + let stride = this._mode === NeoPixelMode.RGBW ? 4 : 3; + pixeloffset = (pixeloffset + this.start) * stride; + + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + let br: number; + if (this._power == PowerSource.Intern) { + br = + this.brightness < total_brightness_limit() + ? this.brightness + : total_brightness_limit(); + } else if (this._power == PowerSource.Extern) { + br = this.brightness; + } + if (br < 255) { + red = (red * br) >> 8; + green = (green * br) >> 8; + blue = (blue * br) >> 8; + } + this.setBufferRGB(pixeloffset, red, green, blue); + } + } + + function total_brightness_limit(): number { + // a WS2812B LED has a current of about 60mA at full brightness with white color + // The TP5400 voltage regulator on the Hiwonder board can deliver around 740mA. To have a little margin we choose a max current of 700mA. + // NOTE sja: Removed !!!exceptional double current!!!! for testing the library on hardware. Having this enabled is not useful. Please set to "external" power supply if you don't want to have power limitation enabled. + return Math.idiv(700 * 255, leds_total * 60) & 0xff; + } + + /** + * creates a color from rgb numbers + * @param r red channel + * @param g green channel + * @param b blue channel + */ + //% weight=86 + //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" + //% block.loc.de="rot %red|grün %green|blau %blue" + //% jsdoc.loc.de="Erstellt eine RGB-Farbe" + //% red.defl=255 red.min=0 red.max=255 + //% blue.defl=255 blue.min=0 blue.max=255 + //% green.defl=255 green.min=0 green.max=255 + //% group="colors" + export function rgb(red: number, green: number, blue: number): number { + return packRGB(red, green, blue); + } + + /** + * creates a color from hsv color picker + * @param hue color + */ + //% weight=85 + //% blockId="neopixel_hsv" block="hue %hue" + //% block.loc.de="Farbe %hue" + //% jsdoc.loc.de="Erstellt eine Farbe" + //% hue.shadow="colorWheelHsvPicker" + //% group="colors" + + export function hsv_picker(hue: number): number { + let mapped_hue = (hue * 360) / 255; + return hsl(mapped_hue, 100, 50); + } + + /** + * Gets the RGB value of a known color + */ + //% weight=84 + //% blockId="neopixel_colors" block="%color" + //% block.loc.de="%color" + //% jsdoc.loc.de="Bekannte RGB-Farben" + //% group="colors" + export function colors(color: NeoPixelColors): number { + return color; + } + + function packRGB(a: number, b: number, c: number): number { + return ((a & 0xff) << 16) | ((b & 0xff) << 8) | (c & 0xff); + } + function unpackR(rgb: number): number { + let r = (rgb >> 16) & 0xff; + return r; + } + function unpackG(rgb: number): number { + let g = (rgb >> 8) & 0xff; + return g; + } + function unpackB(rgb: number): number { + let b = rgb & 0xff; + return b; + } + + /** + * Converts a hue saturation luminosity value into a RGB color + * @param h hue from 0 to 360 + * @param s saturation from 0 to 99 + * @param l luminosity from 0 to 99 + */ + export function hsl(h: number, s: number, l: number): number { + h = Math.round(h); + s = Math.round(s); + l = Math.round(l); + + h = h % 360; + s = Math.clamp(0, 99, s); + l = Math.clamp(0, 99, l); + let c = Math.idiv(((100 - Math.abs(2 * l - 100)) * s) << 8, 10000); //chroma, [0,255] + let h1 = Math.idiv(h, 60); //[0,6] + let h2 = Math.idiv((h - h1 * 60) * 256, 60); //[0,255] + let temp = Math.abs((h1 % 2 << 8) + h2 - 256); + let x = (c * (256 - temp)) >> 8; //[0,255], second largest component of this color + let r$: number; + let g$: number; + let b$: number; + if (h1 == 0) { + r$ = c; + g$ = x; + b$ = 0; + } else if (h1 == 1) { + r$ = x; + g$ = c; + b$ = 0; + } else if (h1 == 2) { + r$ = 0; + g$ = c; + b$ = x; + } else if (h1 == 3) { + r$ = 0; + g$ = x; + b$ = c; + } else if (h1 == 4) { + r$ = x; + g$ = 0; + b$ = c; + } else if (h1 == 5) { + r$ = c; + g$ = 0; + b$ = x; + } + let m = Math.idiv(Math.idiv((l * 2) << 8, 100) - c, 2); + let r = r$ + m; + let g = g$ + m; + let b = b$ + m; + return packRGB(r, g, b); + } + + export enum HueInterpolationDirection { + Clockwise, + CounterClockwise, + Shortest, + } + + /** + * Erstelle ein neues Matrix Objekt + * @param pin Pin an welchem die Matrize angeschlossen ist + * @param size Dimension des Panels in Breite x Höhe + * @param power_source Spannungsquelle welche die LED's versorgt (intern/extern) + */ + //% blockId="Matrix_Create" + //% block="matrix auf Pin %pin|mit einer Grösse von %size| Spannungsquelle %power_source" + //% weight=100 + //% power_source.defl=PowerSource.Intern + //% subcategory=Matrix + //% parts="neopixel" + //% blockSetVariable=matrix + //% group="Setup" + export function create_matrix( + pin: HiwonderMatrixPins, + size: matrixSizes, + power_source: PowerSource + ): Matrix { + let matrix = new Matrix(); + let w, h; + switch (size) { + case matrixSizes.small_8x8: + w = 8; + h = 8; + break; + case matrixSizes.medium_32x8: + w = 32; + h = 8; + break; + case matrixSizes.large_64_8: + w = 64; + h = 8; + break; + case matrixSizes.medium_16x16: + w = 16; + h = 16; + break; + } + + let p: HiwonderPins; + switch (pin) { + case HiwonderMatrixPins.P1: + p = HiwonderPins.P1; + break; + case HiwonderMatrixPins.P2: + p = HiwonderPins.P2; + break; + case HiwonderMatrixPins.P13: + p = HiwonderPins.P13; + break; + case HiwonderMatrixPins.P14: + p = HiwonderPins.P14; + break; + case HiwonderMatrixPins.P16: + p = HiwonderPins.P16; + break; + } + matrix.strip = informatiktheater.create(p, h * w, power_source); + matrix.Width = w; + matrix.Height = h; + + return matrix; + } + + export class Matrix { + strip: informatiktheater.Strip; + Width: number; + Height: number; + + //%blockId="Matrix_show" block="%matrix| anzeigen" + //%weight=10 + //% subcategory=Matrix + //% group="Kontrolle" + show(): void { + this.strip.show(); + } + + //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-255) %setpoint" + //%weight=80 + //%setpoint.defl=32 + //%setpoint.min=0 + //%setpoint.max=255 + //% subcategory=Matrix + //% group="Kontrolle" + setBrightness(setpoint: number): void { + this.strip.setBrightness(setpoint); + } + + /** + * Clear all LED's + * You have to call ``show`` afterwards + */ + //%blockId="Matrix_clear" block="%matrix| ausschalten" + //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." + //%weight=8 + //% subcategory=Matrix + //% group="Kontrolle" + clear(): void { + this.strip.clear(); + } + + /** + * Setzt eine Farbe auf einem bestimmten Pixel in einer LED Matrize. + * Das Koordinaten System für eine oben links Anfangende Matrize ist wie folgt: + * ----> X + * | + * | + * | + * v + * Y + * Die Anordnung für alle ungeraden Spalten ist von unten nach oben (Zig-Zag) + * Die Pixel gehen von Index 0 bis Breite/Länge - 1 + */ + //%blockId="Matrix_setPixel" block="%matrix| setze Pixel x %x| y %y| auf Farbe %colour" + //%weight=70 + //%colour.shadow=neopixel_colors + //% subcategory=Matrix + //% group="Kontrolle" + setPixel(x: number, y: number, colour: number): void { + console.log("matrix: show color : " + colour); + if (x < 0 || x > this.Width || y < 0 || y > this.Height) { + //If the pixel does not fit on screen, do not draw it + return; + } + if (x % 2 == 0) { + //Because of the zig-zag formation of the panel all even rows (including 0) are drawn top to bottom + this.strip.setPixelColor(y + x * this.Height, colour); + } else { + //While all odd rows are drawn bottom to top + this.strip.setPixelColor(this.Height - 1 - y + x * this.Height, colour); + } + } + + /** + * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift. + * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden + */ + //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit: %speed|Farbe: %colour" + //% weight=75 + //% subcategory=Matrix + //% colour.shadow=neopixel_colors + //% speed.min=1 speed.max=200 speed.defl=20 + //% group="Features" + scrollText(text: string, speed: number, colour: number): void { + this.strip.clear(); + for (let Xpos = this.Width; Xpos > -6 * text.length; Xpos--) { + //for loop to scroll across the entire matrix + for (let letter = 0; letter < text.length; letter++) { + //for loop to retrieve all the letters from the text + let x_pointer = Xpos + 6 * letter; + if (((Xpos + 6 * letter) < this.Width) && ((Xpos + 6 * letter) > -6)){ + let bitmap = getLettermap(text.charAt(letter)); + this.drawBitmapVcentered(bitmap, Xpos + 6 * letter, 6, 8, colour); + } + } + this.strip.show(); + basic.pause(1000 / speed); + this.strip.clear(); + } + } + + /** + * Zeige Text auf Matrix mit fixer 6x8 Pixel Schrift. Der Text ist vertikal mittig-zentriert. + * Es muss anschliessend ``anzeigen`` aufgerufen werden. + */ + //% blockId="Matrix_text" block="%matrix Text: %text|Position: %x_offset|Farbe: %colour" + //% weight=74 + //% subcategory=Matrix + //% colour.shadow=neopixel_colors + //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 + //% group="Features" + showText(text: string, x_offset: number, colour: number): void { + for (let letter = 0; letter < text.length; letter++) { + //for loop to retrieve all the letters from te text + let bitmap = getLettermap(text.charAt(letter)); + this.drawBitmapVcentered(bitmap, x_offset + 6 * letter, 6, 8, colour); + } + this.strip.show(); + } + + /** + * Zeige vordefinierte Icons auf 16x16 grosser Matrixe an. + * Hat die Matrix eine andere Grösse, wird nichts angezeigt. + */ + //% blockId="Matrix_icons" block="%matrix Icon: %icon|Farbe: %colour" + //% weight=76 + //% subcategory=Matrix + //% colour.shadow=neopixel_colors + //% group="Features" + draw_icon(icon: IconIndex, colour: number): void { + if (this.Height != 16 || this.Width != 16) { + return; + } + let icon_data = Icons[icon]; + this.drawBitmapIcon16x16(icon_data, 16, 16, colour); + this.strip.show(); + } + + drawBitmapIcon16x16( + bitmap: number[], + width: number, + height: number, + colour: number + ): void { + console.log("draw bitmap[]= " + JSON.stringify(bitmap)); + for (let bitmask = 0; bitmask < width; bitmask++) { + if (!(bitmask % 2)) { + //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top + for (let Ypos = height; Ypos >= 0; Ypos--) { + if (bitmap[Ypos] & (0x8000 >> bitmask)) { + //draw the pixel when there is a "1" in the bitmap + this.strip.setPixelColor( + bitmask * this.Height + Ypos + (this.Height - 16) / 2, + colour + ); + } + } + } else { + //else draw from top to bottom + for (let Ypos = 0; Ypos < this.Height; Ypos++) { + if (bitmap[15 - Ypos] & (0x8000 >> bitmask)) { + this.strip.setPixelColor( + bitmask * this.Height + Ypos + (this.Height - 16) / 2, + colour + ); + } + } + } + } + } + + drawBitmapVcentered( + bitmap: number[], + x: number, + width: number, + height: number, + colour: number + ): void { + console.log("draw bitmap[]= " + JSON.stringify(bitmap)); + for (let bitmask = 0; bitmask < width; bitmask++) { + if (!((x + bitmask) % 2)) { + //Zigzag pixel string: if the row that's being drawn to (Xpos+bitmask) is odd, then draw from bottom to top + for (let Ypos = height; Ypos >= 0; Ypos--) { + if (bitmap[Ypos] & (0x80 >> bitmask)) { + //draw the pixel when there is a "1" in the bitmap + this.strip.setPixelColor( + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } else { + //else draw from top to bottom + for (let Ypos = 0; Ypos < this.Height; Ypos++) { + if (bitmap[7 - Ypos] & (0x80 >> bitmask)) { + this.strip.setPixelColor( + (x + bitmask) * this.Height + Ypos + (this.Height - 8) / 2, + colour + ); + } + } + } + } + } + + //% blockId="neopixel_set_matrix_16" block="Matrix %matrix %c_0|%c_1|%c_2|%c_3|%c_4|%c_5|%c_6|%c_7|%c_8|%c_9|%c_10|%c_11|%c_12|%c_13|%c_14|%c_15" weight=100 + //% subcategory=Matrix + //% group="Features" weight=50 + //% c_0.shadow=color_for_led_16 + //% c_1.shadow=color_for_led_16 + //% c_2.shadow=color_for_led_16 + //% c_3.shadow=color_for_led_16 + //% c_4.shadow=color_for_led_16 + //% c_5.shadow=color_for_led_16 + //% c_6.shadow=color_for_led_16 + //% c_7.shadow=color_for_led_16 + //% c_8.shadow=color_for_led_16 + //% c_9.shadow=color_for_led_16 + //% c_10.shadow=color_for_led_16 + //% c_11.shadow=color_for_led_16 + //% c_12.shadow=color_for_led_16 + //% c_13.shadow=color_for_led_16 + //% c_14.shadow=color_for_led_16 + //% c_15.shadow=color_for_led_16 + setMatrix_16(c_0: ColorPattern, c_1: ColorPattern, c_2: ColorPattern, c_3: ColorPattern, c_4: ColorPattern, c_5: ColorPattern, c_6: ColorPattern, c_7: ColorPattern, c_8: ColorPattern, c_9: ColorPattern, c_10: ColorPattern, c_11: ColorPattern, c_12: ColorPattern, c_13: ColorPattern, c_14: ColorPattern, c_15: ColorPattern): void { + let color = [c_0, c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, c_15] + + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + this.setPixel(x, y, color[y].getColors()[x]) + } + } + this.show(); + } + + //% blockId="neopixel_set_matrix_32x8" block="Matrix %matrix %c_0|%c_1|%c_2|%c_3|%c_4|%c_5|%c_6|%c_7|%c_8|%c_9|%c_10|%c_11|%c_12|%c_13|%c_14|%c_15" weight=99 + //% subcategory=Matrix + //% group="Features" weight=49 + //% c_0.shadow=color_for_led_32 + //% c_1.shadow=color_for_led_32 + //% c_2.shadow=color_for_led_32 + //% c_3.shadow=color_for_led_32 + //% c_4.shadow=color_for_led_32 + //% c_5.shadow=color_for_led_32 + //% c_6.shadow=color_for_led_32 + //% c_7.shadow=color_for_led_32 + setMatrix_32x8(c_0: ColorPattern, c_1: ColorPattern, c_2: ColorPattern, c_3: ColorPattern, c_4: ColorPattern, c_5: ColorPattern, c_6: ColorPattern, c_7: ColorPattern): void { + let color = [c_0, c_1, c_2, c_3, c_4, c_5, c_6, c_7] + + for (let y = 0; y < 8; y++) { + for (let x = 0; x < 32; x++) { + this.setPixel(x, y, color[y].getColors()[x]) + } + } + this.show(); + } + } // end matrix class + + //Take in a string-character and return a bitmap to draw on the display + function getLettermap(char: string): number[] { + let letterMap: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; + let offset = char.charCodeAt(0) - 32; //Convert the ASCII-Character to it's code to generate the offset in the font-array + if (offset >= 0) { + for (let i = 0; i < 8; i++) { + //Every character has 8 arguments in the array, so multiply the offset by 8, and then take ne next 8 arguments as the value for the correct bitmap. + letterMap[i] = font8x3.getNumber(NumberFormat.UInt8BE, offset * 8 + i); + } + } + return letterMap; + } + + /** + * Returns list of 16 color choices for the LEDs + */ + //% blockId="color_for_led_16" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8$c_9$c_10$c_11$c_12$c_13$c_14$c_15$c_16" + //% weight=80 group="colors" + //% c_1.shadow="brightColorNumberPicker" + //% c_2.shadow="brightColorNumberPicker" + //% c_3.shadow="brightColorNumberPicker" + //% c_4.shadow="brightColorNumberPicker" + //% c_5.shadow="brightColorNumberPicker" + //% c_6.shadow="brightColorNumberPicker" + //% c_7.shadow="brightColorNumberPicker" + //% c_8.shadow="brightColorNumberPicker" + //% c_9.shadow="brightColorNumberPicker" + //% c_10.shadow="brightColorNumberPicker" + //% c_11.shadow="brightColorNumberPicker" + //% c_12.shadow="brightColorNumberPicker" + //% c_13.shadow="brightColorNumberPicker" + //% c_14.shadow="brightColorNumberPicker" + //% c_15.shadow="brightColorNumberPicker" + //% c_16.shadow="brightColorNumberPicker" + //% c_1.defl='#000000' + //% c_2.defl='#000000' + //% c_3.defl='#000000' + //% c_4.defl='#000000' + //% c_5.defl='#000000' + //% c_6.defl='#000000' + //% c_7.defl='#000000' + //% c_8.defl='#000000' + //% c_9.defl='#000000' + //% c_10.defl='#000000' + //% c_11.defl='#000000' + //% c_12.defl='#000000' + //% c_13.defl='#000000' + //% c_14.defl='#000000' + //% c_15.defl='#000000' + //% c_16.defl='#000000' + //% inlineInputMode=inline + export function colorForLed_16(c_1: number, c_2: number, c_3: number, c_4: number, c_5: number, c_6: number, c_7: number, c_8: number, c_9: number, c_10: number, c_11: number, c_12: number, c_13: number, c_14: number, c_15: number, c_16: number): ColorPattern { + return new ColorPattern([c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, c_15, c_16]); + } + + + /** + * Returns list of 32 color choices for the LEDs + */ + //% blockId="color_for_led_32" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8|$c_9|$c_10|$c_11|$c_12|$c_13|$c_14|$c_15|$c_16|$c_17|$c_18|$c_19|$c_20|$c_21|$c_22|$c_23|$c_24|$c_25|$c_26|$c_27|$c_28|$c_29|$c_30|$c_31|$c_32|" + //% weight=70 group="colors" + //% c_1.shadow="brightColorNumberPicker" + //% c_2.shadow="brightColorNumberPicker" + //% c_3.shadow="brightColorNumberPicker" + //% c_4.shadow="brightColorNumberPicker" + //% c_5.shadow="brightColorNumberPicker" + //% c_6.shadow="brightColorNumberPicker" + //% c_7.shadow="brightColorNumberPicker" + //% c_8.shadow="brightColorNumberPicker" + //% c_9.shadow="brightColorNumberPicker" + //% c_10.shadow="brightColorNumberPicker" + //% c_11.shadow="brightColorNumberPicker" + //% c_12.shadow="brightColorNumberPicker" + //% c_13.shadow="brightColorNumberPicker" + //% c_14.shadow="brightColorNumberPicker" + //% c_15.shadow="brightColorNumberPicker" + //% c_16.shadow="brightColorNumberPicker" + //% c_17.shadow="brightColorNumberPicker" + //% c_18.shadow="brightColorNumberPicker" + //% c_19.shadow="brightColorNumberPicker" + //% c_20.shadow="brightColorNumberPicker" + //% c_21.shadow="brightColorNumberPicker" + //% c_22.shadow="brightColorNumberPicker" + //% c_23.shadow="brightColorNumberPicker" + //% c_24.shadow="brightColorNumberPicker" + //% c_25.shadow="brightColorNumberPicker" + //% c_26.shadow="brightColorNumberPicker" + //% c_27.shadow="brightColorNumberPicker" + //% c_28.shadow="brightColorNumberPicker" + //% c_29.shadow="brightColorNumberPicker" + //% c_30.shadow="brightColorNumberPicker" + //% c_31.shadow="brightColorNumberPicker" + //% c_32.shadow="brightColorNumberPicker" + //% c_1.defl='#000000' + //% c_2.defl='#000000' + //% c_3.defl='#000000' + //% c_4.defl='#000000' + //% c_5.defl='#000000' + //% c_6.defl='#000000' + //% c_7.defl='#000000' + //% c_8.defl='#000000' + //% c_9.defl='#000000' + //% c_10.defl='#000000' + //% c_11.defl='#000000' + //% c_12.defl='#000000' + //% c_13.defl='#000000' + //% c_14.defl='#000000' + //% c_15.defl='#000000' + //% c_16.defl='#000000' + //% c_17.defl='#000000' + //% c_18.defl='#000000' + //% c_19.defl='#000000' + //% c_20.defl='#000000' + //% c_21.defl='#000000' + //% c_22.defl='#000000' + //% c_23.defl='#000000' + //% c_24.defl='#000000' + //% c_25.defl='#000000' + //% c_26.defl='#000000' + //% c_27.defl='#000000' + //% c_28.defl='#000000' + //% c_29.defl='#000000' + //% c_30.defl='#000000' + //% c_31.defl='#000000' + //% c_32.defl='#000000' + //% inlineInputMode=inline + export function colorForLed_32(c_1: number, c_2: number, c_3: number, c_4: number, c_5: number, c_6: number, c_7: number, c_8: number, c_9: number, c_10: number, c_11: number, c_12: number, c_13: number, c_14: number, c_15: number, c_16: number, + c_17: number, c_18: number, c_19: number, c_20: number, c_21: number, c_22: number, c_23: number, c_24: number, c_25: number, c_26: number, c_27: number, c_28: number, c_29: number, c_30: number, c_31: number, c_32: number): ColorPattern { + return new ColorPattern([c_1, c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, c_15, c_16, + c_17, c_18, c_19, c_20, c_21, c_22, c_23, c_24, c_25, c_26, c_27, c_28, c_29, c_30, c_31, c_32]); + } export enum startbit_ultrasonicPort { port1 = 0x01, port2 = 0x02, } - export enum startbit_PinIOStatus { - //% block="Off" - //% block.loc.de="Aus" - Low = 0x00, - //% block="On" - //% block.loc.de="Ein" - Hight = 0x01, - } - export function startbit_Init() { - startbit_initRGBLight(); serial.redirect(SerialPin.P12, SerialPin.P8, BaudRate.BaudRate115200); basic.forever(() => { @@ -81,8 +1319,6 @@ namespace informatiktheater { let handleCmd: string = ""; let currentVoltage: number = 0; - let lhRGBLight: StartbitRGBLight.LHstartbitRGBLight; - let lhRGBLightBelt: StartbitRGBLight.LHstartbitRGBLight; let MESSAGE_MAC = 0xff; let MESSAGE_ANGLE = 0x100; @@ -106,15 +1342,7 @@ namespace informatiktheater { } } } - if (cmd.charAt(0).compare("C") == 0 && cmd.length == 11) { - if (lhRGBLightBelt != null) { - for (let i = 0; i < 10; i++) { - let color = converOneChar(cmd.charAt(i + 1)); - if (color != -1) lhRGBLightBelt.setPixelColor(i, color); - } - lhRGBLightBelt.show(); - } - } + if (cmd.charAt(0).compare("C") == 0 && cmd.length == 11) {} if (cmd.charAt(0).compare("M") == 0 && cmd.length == 18) { control.raiseEvent(MESSAGE_MAC, 1); } @@ -241,6 +1469,76 @@ namespace informatiktheater { basic.pause(1); } + + /** + * Set the speed of motor 1, 2 or both with speed (0-100) + */ + //% weight=96 blockId=startbit_setMotorSpeed + //% block="Set %motor| in direction %direction| with speed %speed (0-100)" + //% block.loc.de="%motor | in Richtung %direction | mit Geschwindigkeit %speed (0-100)" + //% speed.min=0 speed.max=100 + //% subcategory=Servo/Motor + //% group=Motor + export function startbit_setMotorSpeed(motor: HiwonderMotors, direction: MotorDirections, speed: number) { + if (speed > 100 || speed < 0 ) { + return; + } + + if (direction == MotorDirections.Forward){ + speed = speed * -1; // in original code, forward direction are negative values + } + + switch (motor) { + case HiwonderMotors.M1: + motor_1_speed = speed; + break; + case HiwonderMotors.M2: + motor_2_speed = speed; + break; + case HiwonderMotors.M12: + motor_1_speed = speed; + motor_2_speed = speed; + break; + } + send_motor_speeds(); + } + + /** + * Stop motor 1, 2 or both + */ + //% weight=94 blockId=startbit_stopMotor + //% block="Stop %motor" + //% block.loc.de="%motor stoppen" + //% subcategory=Servo/Motor + //% group=Motor + export function startbit_stopMotor(motor: HiwonderMotors) { + + switch (motor) { + case HiwonderMotors.M1: + motor_1_speed = 0; + break; + case HiwonderMotors.M2: + motor_2_speed = 0; + break; + case HiwonderMotors.M12: + motor_1_speed = 0; + motor_2_speed = 0; + break; + } + send_motor_speeds(); + } + + function send_motor_speeds(){ + let buf = pins.createBuffer(6); + buf[0] = 0x55; + buf[1] = 0x55; + buf[2] = 0x04; + buf[3] = 0x32;//cmd type + buf[4] = motor_1_speed; + buf[5] = motor_2_speed; + serial.writeBuffer(buf); + } + const APDS9960_I2C_ADDR = 0x39; const APDS9960_ID_1 = 0xa8; const APDS9960_ID_2 = 0x9c; @@ -452,8 +1750,8 @@ namespace informatiktheater { //% weight=1 //% blockId=ultrasonic_init //% block="initialize ultrasonic |%pin" - //% block.loc.de="initialisiere Ultraschall|%port" - //% subcategory=Ultraschall + //% block.loc.de="initialisiere Ultraschall|%pin" + //% group="Ultraschall" //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { @@ -476,7 +1774,7 @@ namespace informatiktheater { //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" //% block.loc.de="Ultraschall|Distanz (cm)" - //% subcategory=Ultraschall + //% group="Ultraschall" export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); pins.setPull(trigPin, PinPullMode.PullNone); @@ -498,70 +1796,6 @@ namespace informatiktheater { return Math.round((distance * 10) / 6 / 58 / 1.6); } - /** - * Initialize RGB - */ - function startbit_initRGBLight() { - if (!lhRGBLight) { - lhRGBLight = StartbitRGBLight.create( - DigitalPin.P15, - 6, // Silvan: Why 6 LEDS?! - StartbitRGBPixelMode.RGB - ); - } - startbit_clearLight(); - } - - /** - * Set the brightness of the LED. This flag only applies to future operation. - * @param brightness a measure of LED brightness in 0-255. eg: 255 - */ - //% blockId="startbit_setBrightness" - //% block="set brightness value to %brightness" - //% block.loc.de="setze Helligkeit auf Wert %brightness" - //% brightness.min=0 brightness.max=255 brightness.defl=255 - //% jsdoc.loc.de="Setze die Hellighkeit der LED. Dies gilt nur zukünftige Operationen." - //% brightness.loc.de="LED Helligkeit zwischen 0 bis 255" - //% weight=100 - //% subcategory=Board-LED - export function startbit_setBrightness(brightness: number): void { - lhRGBLight.setBrightness(brightness); - lhRGBLight.show(); - } - - //% weight=99 blockId=startbit_setPixelRGBArgs - //% block="set|%lightoffset|color to %rgb" - //% block.loc.de="setze Farbe von|%lightoffset|auf %rgb" - //% subcategory=Board-LED - export function startbit_setPixelRGBArgs( - lightoffset: StartbitLights, - rgb: StartbitRGBColors - ) { - lhRGBLight.setPixelColor(lightoffset, rgb); - lhRGBLight.show(); - } - - //% weight=97 blockId=startbit_showLight - //% block="show board-LED" - //% block.loc.de="Board-LED anzeigen" - //% jsdoc.loc.de="Zeige die gefärbten Lichter. Muss ausgeführt werden nachdem eine Lichtfarbe gesetzt wurde!" - //% subcategory=Board-LED - export function startbit_showLight() { - lhRGBLight.show(); - } - - /** - * Clear the color of the colored lights and turn off the lights. - */ - //% weight=96 blockGap=50 blockId=startbit_clearLight - //% block="clear board-LED" - //% block.loc.de="Board-LED ausschalten" - //% jsdoc.loc.de="Setze Farbe zurück und schalte LED aus" - //% subcategory=Board-LED - export function startbit_clearLight() { - lhRGBLight.clear(); - } - // TODO: This will NOT clip values! should we add clipping ?! function mapValue( x: number, @@ -643,9 +1877,9 @@ namespace informatiktheater { * Binds code to be executed to onPulsed event with value high */ //% weight=9 - //% block="Trittmatte pressed|on %port" - //% block.loc.de="Trittmatte gedrückt|auf|%port" - //% subcategory=Trittmatte + //% block="Push-button pressed|on %port" + //% block.loc.de="Taster gedrückt|auf|%port" + //% group="Taster" export function trittmatte_pressed( port: startbit_trittmattePort, handler: () => void @@ -676,9 +1910,9 @@ namespace informatiktheater { * Binds code to be executed to onPulsed event with value low */ //% weight=8 - //% block="Trittmatte released|on %port" - //% block.loc.de="Trittmatte losgelassen|auf|%port" - //% subcategory=Trittmatte + //% block="Push-button released|on %port" + //% block.loc.de="Taster losgelassen|auf|%port" + //% group="Taster" export function trittmatte_released( port: startbit_trittmattePort, handler: () => void @@ -710,9 +1944,9 @@ namespace informatiktheater { * The initial state will always be set to zero and the variable has local scope only! */ //% weight=7 - //% block="Trittmatte on/off|on %port |state " - //% block.loc.de="Trittmatte ein/aus|auf %port |Status" - //% subcategory=Trittmatte + //% block="Push-button on/off|on %port |state " + //% block.loc.de="Taster ein/aus|auf %port |Status" + //% group="Taster" //% draggableParameters //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" export function trittmatte_einschalten( diff --git a/pxt.json b/pxt.json index c986dbf..b1f3f9a 100644 --- a/pxt.json +++ b/pxt.json @@ -1,13 +1,13 @@ { "name": "informatiktheater", - "version": "0.0.3", + "version": "0.1.0", "description": "Blocks for Informatiktheater", "license": "MIT", "dependencies": { "core": "file:../core", "ws2812b": "github:microsoft/pxt-ws2812b#v0.1.2" }, - "files": ["README.md", "StartbitV2.ts", "StartbitRGBLight.ts", "neopixel.ts"], + "files": ["README.md", "StartbitV2.ts"], "testFiles": ["test.ts", "neotest.ts"], "public": true, "supportedTargets": ["microbit"], From 4331f4404ea1e1b49c7f22da0bda2e5aee943a9e Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 23 Mar 2024 23:36:49 +0100 Subject: [PATCH 212/253] Beschriftung Matrixenbilder --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index a27f1a2..82d1b07 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -68,15 +68,15 @@ enum MotorDirections { * Named indexes for pre-defined icons below */ enum IconIndex { - //% block="Smiley hoch" + //% block="Smiley lachen" smiley_high, - //% block="Smiley biz hoch" + //% block="Smiley schmunzeln" smiley_b_high, //% block="Smiley Strich" smiley_underscore, - //% block="Smiley biz runter" + //% block="Smiley betrübt" smiley_b_down, - //% block="Smiley runter" + //% block="Smiley traurig" smiley_down, //% block="Herz gross" heart_big, From ca79377f5397b915219c592bec12411d01142b49 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 23 Mar 2024 23:41:48 +0100 Subject: [PATCH 213/253] Pin order changed --- StartbitV2.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 82d1b07..137bd88 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -199,22 +199,22 @@ enum matrixSizes { * Available pins on ports (connectors) */ enum HiwonderPins { - P1 = DigitalPin.P1, P2 = DigitalPin.P2, - P13 = DigitalPin.P13, + P1 = DigitalPin.P1, P14 = DigitalPin.P14, - Onboard= DigitalPin.P15, + P13 = DigitalPin.P13, P16 = DigitalPin.P16, + Board= DigitalPin.P15, } /** * Available pins on ports (connectors) */ enum HiwonderMatrixPins { - P1 = DigitalPin.P1, P2 = DigitalPin.P2, - P13 = DigitalPin.P13, + P1 = DigitalPin.P1, P14 = DigitalPin.P14, + P13 = DigitalPin.P13, P16 = DigitalPin.P16, } From 069d449cb63c0dd2f6a8116a9ce38580b80de412 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 23 Mar 2024 23:44:00 +0100 Subject: [PATCH 214/253] onboard board --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 137bd88..c39f5e3 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -341,7 +341,7 @@ namespace informatiktheater { case HiwonderPins.P14: p = DigitalPin.P14; break; - case HiwonderPins.Onboard: + case HiwonderPins.Board: p = DigitalPin.P15; break; case HiwonderPins.P16: From 7bd78b42906948aad2a44260a172aade694fc065 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sat, 23 Mar 2024 23:47:39 +0100 Subject: [PATCH 215/253] order Matrixsizes --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index c39f5e3..1023f1c 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -185,14 +185,14 @@ enum NeoPixelMode { * NeoPixel matrix size definiitons */ enum matrixSizes { - //% block="8x8" - small_8x8, + //% block="16x16" + medium_16x16, //% block="32x8" medium_32x8, //% block="64x8" large_64_8, - //% block="16x16" - medium_16x16, + //% block="8x8" + small_8x8, } /** From 4c2fd11c9bfe75e5d71a49333a82d691511298d0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sun, 24 Mar 2024 00:04:35 +0100 Subject: [PATCH 216/253] various --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1023f1c..5115d5a 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -567,7 +567,7 @@ namespace informatiktheater { * @param brightness a measure of LED brightness in 0-255. eg: 100 */ //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" - //% block.loc.de="%strip|setze Helligkeit %brightness" + //% block.loc.de="%strip|setze Helligkeit auf (0-255) %brightness" //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." //% brightness.defl=255 brightness.min=0 brightness.max=255 //% strip.defl=strip From 07c1b4716bf3ae077f1e203b11a38e7b4979bc59 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Sun, 24 Mar 2024 00:08:31 +0100 Subject: [PATCH 217/253] Update StartbitV2.ts --- StartbitV2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 5115d5a..3fbbdd4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -870,9 +870,9 @@ namespace informatiktheater { let matrix = new Matrix(); let w, h; switch (size) { - case matrixSizes.small_8x8: - w = 8; - h = 8; + case matrixSizes.medium_16x16: + w = 16; + h = 16; break; case matrixSizes.medium_32x8: w = 32; @@ -882,9 +882,9 @@ namespace informatiktheater { w = 64; h = 8; break; - case matrixSizes.medium_16x16: - w = 16; - h = 16; + case matrixSizes.small_8x8: + w = 8; + h = 8; break; } From 092be8303f96b23a967bed13303b372644690a92 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:26:20 +0100 Subject: [PATCH 218/253] Update StartbitV2.ts --- StartbitV2.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 3fbbdd4..a3c1b22 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -329,24 +329,24 @@ namespace informatiktheater { // we can't use string literals here and can't change DigitalPin to non constant enum let p; switch (pin) { + case HiwonderPins.P2: + p = DigitalPin.P2; + break; case HiwonderPins.P1: p = DigitalPin.P1; break; - case HiwonderPins.P2: - p = DigitalPin.P2; + case HiwonderPins.P14: + p = DigitalPin.P14; break; case HiwonderPins.P13: p = DigitalPin.P13; break; - case HiwonderPins.P14: - p = DigitalPin.P14; + case HiwonderPins.P16: + p = DigitalPin.P16; break; case HiwonderPins.Board: p = DigitalPin.P15; break; - case HiwonderPins.P16: - p = DigitalPin.P16; - break; } strip.setPin(p); return strip; @@ -1879,6 +1879,7 @@ namespace informatiktheater { //% weight=9 //% block="Push-button pressed|on %port" //% block.loc.de="Taster gedrückt|auf|%port" + //% subcategory="Sensoren" //% group="Taster" export function trittmatte_pressed( port: startbit_trittmattePort, From 18973ca0b0ee223e4e76a3f16e90861de699c0bf Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:28:35 +0100 Subject: [PATCH 219/253] Update StartbitV2.ts --- StartbitV2.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index a3c1b22..75279dd 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1913,6 +1913,7 @@ namespace informatiktheater { //% weight=8 //% block="Push-button released|on %port" //% block.loc.de="Taster losgelassen|auf|%port" + //% subcategory="Sensoren" //% group="Taster" export function trittmatte_released( port: startbit_trittmattePort, @@ -1947,6 +1948,7 @@ namespace informatiktheater { //% weight=7 //% block="Push-button on/off|on %port |state " //% block.loc.de="Taster ein/aus|auf %port |Status" + //% subcategory="Sensoren" //% group="Taster" //% draggableParameters //% jsdoc.loc.de="Bindet auszuführenden Code bei einem PulsEvent mit Wert 'hoch' an Event Handler. Der Anfangszustand wird immer auf Null sein. Die Zustandsvariabel hat nur lokalen Scope!" From 5cb7a071ec0e9d7191302f7b2ed73b9d65d6c8f0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:31:59 +0100 Subject: [PATCH 220/253] Update StartbitV2.ts --- StartbitV2.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 75279dd..52b6a6d 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1747,10 +1747,11 @@ namespace informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=1 + //% weight=5 //% blockId=ultrasonic_init //% block="initialize ultrasonic |%pin" //% block.loc.de="initialisiere Ultraschall|%pin" + //% subcategory="Sensoren" //% group="Ultraschall" //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { @@ -1770,10 +1771,11 @@ namespace informatiktheater { /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=90 + //% weight=1 //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" //% block.loc.de="Ultraschall|Distanz (cm)" + //% subcategory="Sensoren" //% group="Ultraschall" export function startbit_ultrasonic(): number { pins.setPull(echoPin, PinPullMode.PullNone); From 62c32847be26b070d676e2bf4a8f183efe7cd1c0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 07:45:13 +0100 Subject: [PATCH 221/253] Update StartbitV2.ts --- StartbitV2.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 52b6a6d..25e80ca 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -271,6 +271,7 @@ namespace informatiktheater { //% value.defl='#ff0000' weight=81 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' + //% subcategory="Stripe" //% group="colors" export function __colorNumberPicker(value: number) { return value; @@ -739,6 +740,7 @@ namespace informatiktheater { //% red.defl=255 red.min=0 red.max=255 //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 + //% subcategory="Stripe" //% group="colors" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); @@ -753,6 +755,7 @@ namespace informatiktheater { //% block.loc.de="Farbe %hue" //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" + //% subcategory="Stripe" //% group="colors" export function hsv_picker(hue: number): number { @@ -767,7 +770,8 @@ namespace informatiktheater { //% blockId="neopixel_colors" block="%color" //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" - //% group="colors" + //% subcategory="Sensoren" + //% group="Stripe" export function colors(color: NeoPixelColors): number { return color; } @@ -986,11 +990,11 @@ namespace informatiktheater { * Scrolle Text über Matrix mit fixer 6x8 Pixel Schrift. * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden */ - //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit: %speed|Farbe: %colour" + //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (0-200): %speed|Farbe: %colour" //% weight=75 //% subcategory=Matrix //% colour.shadow=neopixel_colors - //% speed.min=1 speed.max=200 speed.defl=20 + //% speed.min=1 speed.max=200 speed.defl=50 //% group="Features" scrollText(text: string, speed: number, colour: number): void { this.strip.clear(); From c1ed2997ed0d083dbc389c8bfb845d838de8f8ad Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 11:56:48 +0100 Subject: [PATCH 222/253] soundbox off --- StartbitV2.ts | 119 +++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 25e80ca..e29fcc1 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1997,68 +1997,68 @@ namespace informatiktheater { this.list = [0]; } - //% weight=99 - //% block="setze $this auf $list " - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=Soundbox - public createSongListArray(list: number[]) { - this.list = list; - this.TrackIndex = 0; - } - - //% weight=98 - //% block="Play next track in list $this" - //% block.loc.de="nächste Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=Soundbox - public playNextTrack() { - if (this.TrackIndex < this.list.length) { - this.TrackIndex += 1; - } else { - this.TrackIndex = 0; - } - } - // - //% weight=97 - //% block="Play previous track in list $this" - //% block.loc.de="vorherige Songnummer in Liste $this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=Soundbox - public playPreviousTrack() { - if (this.TrackIndex <= 0) { - this.TrackIndex == 0; - } else { - this.TrackIndex--; - } - } - - //% weight=95 - //% block="current song number in list %this" - //% block.loc.de="Aktuelle Songnummer in liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=Soundbox - public currentTrack(): number { - return this.list[this.TrackIndex]; - } - - //% weight=96 - //% block="Back to first song in list %this" - //% block.loc.de="zurück zur ersten Songnummer in Liste %this" - //% this.defl=Songliste - //% this.shadow=variables_get - //% subcategory=Soundbox - public gotoFirstTrack() { - this.TrackIndex = 0; - } - } +// //% weight=99 +// //% block="setze $this auf $list " +// //% this.defl=Songliste +// //% this.shadow=variables_get +// //% subcategory=Soundbox +// public createSongListArray(list: number[]) { +// this.list = list; +// this.TrackIndex = 0; +// } + +// //% weight=98 +// //% block="Play next track in list $this" +// //% block.loc.de="nächste Songnummer in Liste $this" +// //% this.defl=Songliste +// //% this.shadow=variables_get +// //% subcategory=Soundbox +// public playNextTrack() { +// if (this.TrackIndex < this.list.length) { +// this.TrackIndex += 1; +// } else { +// this.TrackIndex = 0; +// } +// } +// // +// //% weight=97 +// //% block="Play previous track in list $this" +// //% block.loc.de="vorherige Songnummer in Liste $this" +// //% this.defl=Songliste +// //% this.shadow=variables_get +// //% subcategory=Soundbox +// public playPreviousTrack() { +// if (this.TrackIndex <= 0) { +// this.TrackIndex == 0; +// } else { +// this.TrackIndex--; +// } +// } + +// //% weight=95 +// //% block="current song number in list %this" +// //% block.loc.de="Aktuelle Songnummer in liste %this" +// //% this.defl=Songliste +// //% this.shadow=variables_get +// //% subcategory=Soundbox +// public currentTrack(): number { +// return this.list[this.TrackIndex]; +// } + +// //% weight=96 +// //% block="Back to first song in list %this" +// //% block.loc.de="zurück zur ersten Songnummer in Liste %this" +// //% this.defl=Songliste +// //% this.shadow=variables_get +// //% subcategory=Soundbox +// public gotoFirstTrack() { +// this.TrackIndex = 0; +// } +// } /** * Creates a song list and automtically set it to a variable - */ + //% weight=100 //% block="create song list" //% block.loc.de="erstelle Songliste" @@ -2069,3 +2069,4 @@ namespace informatiktheater { return new SongList(); } } + */ From 7fca1c4aa0ccfbd919c770abbac898f778475d77 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:08:45 +0100 Subject: [PATCH 223/253] order --- StartbitV2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e29fcc1..95f4e87 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -398,10 +398,10 @@ namespace informatiktheater { //% startHue.defl=1 //% endHue.defl=255 //% endHue.shadow="colorWheelHsvPicker" - //% weight=97 + //% weight=20 //% parts="neopixel" - //% subcategory=Stripe - //% group="Features" + //% subcategory="Stripe" + //% group="Kontrolle" showRainbow(startHue: number = 1, endHue: number = 255) { if (this._length <= 0) return; @@ -556,7 +556,7 @@ namespace informatiktheater { //% strip.defl=strip //% weight=60 //% subcategory=Stripe - //% group="Setup" + //% group="Features" length() { return this._length; } @@ -570,12 +570,12 @@ namespace informatiktheater { //% blockId="neopixel_set_brightness" block="%strip|set brightness %brightness" //% block.loc.de="%strip|setze Helligkeit auf (0-255) %brightness" //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." - //% brightness.defl=255 brightness.min=0 brightness.max=255 + //% brightness.defl=150 brightness.min=0 brightness.max=255 //% strip.defl=strip //% weight=99 //% parts="neopixel" //% subcategory=Stripe - //% group="Kontrolle" + //% group="Setup" setBrightness(brightness: number): void { this.brightness = brightness & 0xff; } From 14bb4007f9530baf86809da4550651bc7daf3aff Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:10:04 +0100 Subject: [PATCH 224/253] Update StartbitV2.ts --- StartbitV2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 95f4e87..d67501f 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -2068,5 +2068,6 @@ namespace informatiktheater { export function createSongList(): SongList { return new SongList(); } + */ } - */ + From 1572e852b42388ddb96ee7f3dae93e6b2001dbaa Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:20:32 +0100 Subject: [PATCH 225/253] changes --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d67501f..2ba6ddb 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -254,7 +254,7 @@ const font8x3 = hex` /* Informatiktheater package */ -//% weight=10 color=#3a4cf7 +//% weight=1 color=#3a4cf7 namespace informatiktheater { let leds_total = 0; @@ -268,7 +268,7 @@ namespace informatiktheater { //% blockId=brightColorNumberPicker block="%value" //% shim=TD_ID colorSecondary="#FFFFFF" //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true - //% value.defl='#ff0000' weight=81 + //% value.defl='#ff0000' weight=100 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" @@ -301,7 +301,7 @@ namespace informatiktheater { //% block="NeoPixel at pin %pin| with %numleds leds| power source %power_source" //% block.loc.de="NeoPixels an Pin %pin|mit %numleds Pixeln| Spannungsquelle %power_source" //% jsdoc.loc.de="Erzeuge einen neuen Treiber für die gegebene Anzahl NeoPixels, die am angegebenen Port angeschlossen sind. Der Modus bestimmt die genaue Bauart der NeoPixel." - //% weight=90 + //% weight=110 //% parts="neopixel" //% power_source.defl=PowerSource.Intern //% subcategory=Stripe @@ -377,8 +377,8 @@ namespace informatiktheater { //% strip.defl=strip //% weight=98 //% parts="neopixel" - //% group="Kontrolle" //% subcategory=Stripe + //% group="Kontrolle" showColor(rgb: number) { rgb = rgb >> 0; this.setAllRGB(rgb); From 51c94505f2b61b40deae9c39977d43aa21c03408 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:23:21 +0100 Subject: [PATCH 226/253] Update StartbitV2.ts --- StartbitV2.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 2ba6ddb..dde0ada 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -2058,16 +2058,16 @@ namespace informatiktheater { /** * Creates a song list and automtically set it to a variable - - //% weight=100 - //% block="create song list" - //% block.loc.de="erstelle Songliste" - //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." - //% blockSetVariable=Songliste - //% subcategory=Soundbox + */ +// //% weight=100 +// //% block="create song list" +// //% block.loc.de="erstelle Songliste" +// //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." +// //% blockSetVariable=Songliste +// //% subcategory=Soundbox export function createSongList(): SongList { return new SongList(); } - */ + } From 180fd3108e65f67b972fd3a84bd036960f6558f5 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:08:46 +0100 Subject: [PATCH 227/253] Update StartbitV2.ts --- StartbitV2.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index dde0ada..37201b5 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1951,7 +1951,7 @@ namespace informatiktheater { * Binds code to be executed to onPulsed event with value high on event handler. * The initial state will always be set to zero and the variable has local scope only! */ - //% weight=7 + //% weight=3 //% block="Push-button on/off|on %port |state " //% block.loc.de="Taster ein/aus|auf %port |Status" //% subcategory="Sensoren" @@ -2065,9 +2065,9 @@ namespace informatiktheater { // //% jsdoc.loc.de="erstellt eine neue Songliste und setzt sie auf eine Variable. Muss im Startblock ausgeführt werden bevor MP3 Box gebraucht werden kann." // //% blockSetVariable=Songliste // //% subcategory=Soundbox - export function createSongList(): SongList { - return new SongList(); - } +// export function createSongList(): SongList { +// return new SongList(); +// } -} +// } From 0d5cac6f76431e5558f5d2e178abf2217b49bfaa Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:10:39 +0100 Subject: [PATCH 228/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 37201b5..bec5f4a 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -2069,5 +2069,5 @@ namespace informatiktheater { // return new SongList(); // } -// } +} From 0f6848644432d73943893cb2bec3150b75ea15d7 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:12:16 +0100 Subject: [PATCH 229/253] Update StartbitV2.ts --- StartbitV2.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bec5f4a..3d348dd 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1988,14 +1988,14 @@ namespace informatiktheater { // MP3 Player stuff - export class SongList { - TrackIndex: number; - list: Array; +// export class SongList { +// TrackIndex: number; +// list: Array; - constructor() { - this.TrackIndex = 0; - this.list = [0]; - } +// constructor() { +// this.TrackIndex = 0; +// this.list = [0]; +// } // //% weight=99 // //% block="setze $this auf $list " From bd50e49a9fddff8a2ccc835fd877212d875d51e0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:23:54 +0100 Subject: [PATCH 230/253] Update StartbitV2.ts --- StartbitV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 3d348dd..6eaab5b 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -572,7 +572,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Setze die Helligkeit der NeoPixel (0-255). Die Änderung betrifft nur zukünftige Operationen! Die höchst möglichste Helligkeit hängt von der Anzahl LED's ab. Die Helligkeit wird bei diesem Schwellwert begrenzt." //% brightness.defl=150 brightness.min=0 brightness.max=255 //% strip.defl=strip - //% weight=99 + //% weight=41 //% parts="neopixel" //% subcategory=Stripe //% group="Setup" @@ -770,8 +770,8 @@ namespace informatiktheater { //% blockId="neopixel_colors" block="%color" //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" - //% subcategory="Sensoren" - //% group="Stripe" + //% subcategory="Stripe" + //% group="colors" export function colors(color: NeoPixelColors): number { return color; } From cdf6fdc546ca6d3ef45df8e02e363a1ecfbd1904 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:42:25 +0100 Subject: [PATCH 231/253] Update StartbitV2.ts --- StartbitV2.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 6eaab5b..56abf52 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -375,7 +375,7 @@ namespace informatiktheater { //% block.loc.de="%strip|zeige Farbe %rgb=neopixel_colors" //% jsdoc.loc.de="Setze alle Pixel auf die angegebene Farbe und rufe ``anzeigen`` auf." //% strip.defl=strip - //% weight=98 + //% weight=50 //% parts="neopixel" //% subcategory=Stripe //% group="Kontrolle" @@ -497,7 +497,7 @@ namespace informatiktheater { //% pixeloffset.defl=0 //% pixeloffset.min=0 //% pixeloffset.max=255 - //% weight=80 + //% weight=44 //% rgb.shadow=neopixel_colors //% parts="neopixel" //% subcategory=Stripe @@ -742,6 +742,7 @@ namespace informatiktheater { //% green.defl=255 green.min=0 green.max=255 //% subcategory="Stripe" //% group="colors" + //% group.loc.de=" Farben" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); } @@ -757,6 +758,7 @@ namespace informatiktheater { //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" //% group="colors" + //% group.loc.de=" Farben" export function hsv_picker(hue: number): number { let mapped_hue = (hue * 360) / 255; @@ -772,6 +774,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" //% group="colors" + //% group.loc.de=" Farben" export function colors(color: NeoPixelColors): number { return color; } @@ -1751,7 +1754,7 @@ namespace informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=5 + //% weight=16 //% blockId=ultrasonic_init //% block="initialize ultrasonic |%pin" //% block.loc.de="initialisiere Ultraschall|%pin" @@ -1775,7 +1778,7 @@ namespace informatiktheater { /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=1 + //% weight=17 //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" //% block.loc.de="Ultraschall|Distanz (cm)" @@ -1882,7 +1885,7 @@ namespace informatiktheater { /** * Binds code to be executed to onPulsed event with value high */ - //% weight=9 + //% weight=11 //% block="Push-button pressed|on %port" //% block.loc.de="Taster gedrückt|auf|%port" //% subcategory="Sensoren" @@ -1916,7 +1919,7 @@ namespace informatiktheater { /** * Binds code to be executed to onPulsed event with value low */ - //% weight=8 + //% weight=12 //% block="Push-button released|on %port" //% block.loc.de="Taster losgelassen|auf|%port" //% subcategory="Sensoren" @@ -1951,7 +1954,7 @@ namespace informatiktheater { * Binds code to be executed to onPulsed event with value high on event handler. * The initial state will always be set to zero and the variable has local scope only! */ - //% weight=3 + //% weight=13 //% block="Push-button on/off|on %port |state " //% block.loc.de="Taster ein/aus|auf %port |Status" //% subcategory="Sensoren" From 5580ca4a16a8b7731b053eb24e87265f12657bdb Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:05:16 +0100 Subject: [PATCH 232/253] Update StartbitV2.ts --- StartbitV2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 56abf52..7568d6c 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -268,11 +268,12 @@ namespace informatiktheater { //% blockId=brightColorNumberPicker block="%value" //% shim=TD_ID colorSecondary="#FFFFFF" //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true - //% value.defl='#ff0000' weight=100 + //% value.defl='#ff0000' weight=29 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" //% group="colors" + //% group.loc.de="Farben" export function __colorNumberPicker(value: number) { return value; } From 31fe4c8ea60dce357bbb8be10102cdd7ae750ead Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:21:39 +0100 Subject: [PATCH 233/253] order --- StartbitV2.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 7568d6c..e00dd44 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -864,7 +864,7 @@ namespace informatiktheater { */ //% blockId="Matrix_Create" //% block="matrix auf Pin %pin|mit einer Grösse von %size| Spannungsquelle %power_source" - //% weight=100 + //% weight=30 //% power_source.defl=PowerSource.Intern //% subcategory=Matrix //% parts="neopixel" @@ -971,10 +971,10 @@ namespace informatiktheater { * Die Pixel gehen von Index 0 bis Breite/Länge - 1 */ //%blockId="Matrix_setPixel" block="%matrix| setze Pixel x %x| y %y| auf Farbe %colour" - //%weight=70 + //%weight=39 //%colour.shadow=neopixel_colors //% subcategory=Matrix - //% group="Kontrolle" + //% group="Features" setPixel(x: number, y: number, colour: number): void { console.log("matrix: show color : " + colour); if (x < 0 || x > this.Width || y < 0 || y > this.Height) { @@ -995,7 +995,7 @@ namespace informatiktheater { * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden */ //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (0-200): %speed|Farbe: %colour" - //% weight=75 + //% weight=33 //% subcategory=Matrix //% colour.shadow=neopixel_colors //% speed.min=1 speed.max=200 speed.defl=50 @@ -1023,7 +1023,7 @@ namespace informatiktheater { * Es muss anschliessend ``anzeigen`` aufgerufen werden. */ //% blockId="Matrix_text" block="%matrix Text: %text|Position: %x_offset|Farbe: %colour" - //% weight=74 + //% weight=35 //% subcategory=Matrix //% colour.shadow=neopixel_colors //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 @@ -1042,7 +1042,7 @@ namespace informatiktheater { * Hat die Matrix eine andere Grösse, wird nichts angezeigt. */ //% blockId="Matrix_icons" block="%matrix Icon: %icon|Farbe: %colour" - //% weight=76 + //% weight=36 //% subcategory=Matrix //% colour.shadow=neopixel_colors //% group="Features" @@ -1124,7 +1124,7 @@ namespace informatiktheater { //% blockId="neopixel_set_matrix_16" block="Matrix %matrix %c_0|%c_1|%c_2|%c_3|%c_4|%c_5|%c_6|%c_7|%c_8|%c_9|%c_10|%c_11|%c_12|%c_13|%c_14|%c_15" weight=100 //% subcategory=Matrix - //% group="Features" weight=50 + //% group="Features" weight=37 //% c_0.shadow=color_for_led_16 //% c_1.shadow=color_for_led_16 //% c_2.shadow=color_for_led_16 @@ -1152,7 +1152,7 @@ namespace informatiktheater { this.show(); } - //% blockId="neopixel_set_matrix_32x8" block="Matrix %matrix %c_0|%c_1|%c_2|%c_3|%c_4|%c_5|%c_6|%c_7|%c_8|%c_9|%c_10|%c_11|%c_12|%c_13|%c_14|%c_15" weight=99 + //% blockId="neopixel_set_matrix_32x8" block="Matrix %matrix %c_0|%c_1|%c_2|%c_3|%c_4|%c_5|%c_6|%c_7|%c_8|%c_9|%c_10|%c_11|%c_12|%c_13|%c_14|%c_15" //% subcategory=Matrix //% group="Features" weight=49 //% c_0.shadow=color_for_led_32 @@ -1192,7 +1192,9 @@ namespace informatiktheater { * Returns list of 16 color choices for the LEDs */ //% blockId="color_for_led_16" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8$c_9$c_10$c_11$c_12$c_13$c_14$c_15$c_16" - //% weight=80 group="colors" + //% subcategory=Matrix + //% group="colors" weight=49 + //% group.loc.de="Farben" //% c_1.shadow="brightColorNumberPicker" //% c_2.shadow="brightColorNumberPicker" //% c_3.shadow="brightColorNumberPicker" @@ -1235,7 +1237,9 @@ namespace informatiktheater { * Returns list of 32 color choices for the LEDs */ //% blockId="color_for_led_32" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8|$c_9|$c_10|$c_11|$c_12|$c_13|$c_14|$c_15|$c_16|$c_17|$c_18|$c_19|$c_20|$c_21|$c_22|$c_23|$c_24|$c_25|$c_26|$c_27|$c_28|$c_29|$c_30|$c_31|$c_32|" - //% weight=70 group="colors" + //% subcategory=Matrix + //% group="colors" weight=47 + //% group.loc.de="Farben" //% c_1.shadow="brightColorNumberPicker" //% c_2.shadow="brightColorNumberPicker" //% c_3.shadow="brightColorNumberPicker" From 0eb80807fde296e53cc36fe0c24fc835d63bde77 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:29:23 +0100 Subject: [PATCH 234/253] minor --- StartbitV2.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e00dd44..f59a6d1 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -927,7 +927,7 @@ namespace informatiktheater { Height: number; //%blockId="Matrix_show" block="%matrix| anzeigen" - //%weight=10 + //%weight=32 //% subcategory=Matrix //% group="Kontrolle" show(): void { @@ -935,7 +935,7 @@ namespace informatiktheater { } //%blockId="Matrix_Brighness" block="%matrix setze Helligkeit auf (0-255) %setpoint" - //%weight=80 + //%weight=31 //%setpoint.defl=32 //%setpoint.min=0 //%setpoint.max=255 @@ -951,7 +951,7 @@ namespace informatiktheater { */ //%blockId="Matrix_clear" block="%matrix| ausschalten" //% jsdoc.loc.de="Schalte alle NeoPixel aus. Damit die Änderung sichtbar wird, muss anschließend ``anzeigen`` aufgerufen werden." - //%weight=8 + //% weight=33 //% subcategory=Matrix //% group="Kontrolle" clear(): void { @@ -971,7 +971,7 @@ namespace informatiktheater { * Die Pixel gehen von Index 0 bis Breite/Länge - 1 */ //%blockId="Matrix_setPixel" block="%matrix| setze Pixel x %x| y %y| auf Farbe %colour" - //%weight=39 + //%weight=40 //%colour.shadow=neopixel_colors //% subcategory=Matrix //% group="Features" @@ -995,11 +995,11 @@ namespace informatiktheater { * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden */ //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (0-200): %speed|Farbe: %colour" - //% weight=33 + //% weight=35 //% subcategory=Matrix //% colour.shadow=neopixel_colors //% speed.min=1 speed.max=200 speed.defl=50 - //% group="Features" + //% group="Features" weight=1 scrollText(text: string, speed: number, colour: number): void { this.strip.clear(); for (let Xpos = this.Width; Xpos > -6 * text.length; Xpos--) { @@ -1027,7 +1027,7 @@ namespace informatiktheater { //% subcategory=Matrix //% colour.shadow=neopixel_colors //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 - //% group="Features" + //% group="Features" weight=2 showText(text: string, x_offset: number, colour: number): void { for (let letter = 0; letter < text.length; letter++) { //for loop to retrieve all the letters from te text From c3384498bb5bdbdae9368153a3884759d476f7fb Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:35:38 +0100 Subject: [PATCH 235/253] Update StartbitV2.ts --- StartbitV2.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index f59a6d1..cf2b5fa 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -742,7 +742,7 @@ namespace informatiktheater { //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 //% subcategory="Stripe" - //% group="colors" + //% group="colors" weight=84 //% group.loc.de=" Farben" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); @@ -752,14 +752,14 @@ namespace informatiktheater { * creates a color from hsv color picker * @param hue color */ - //% weight=85 + //% //% blockId="neopixel_hsv" block="hue %hue" //% block.loc.de="Farbe %hue" //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" - //% group="colors" - //% group.loc.de=" Farben" + //% group="colors" weight=85 + //% group.loc.de="Farben" export function hsv_picker(hue: number): number { let mapped_hue = (hue * 360) / 255; @@ -769,13 +769,14 @@ namespace informatiktheater { /** * Gets the RGB value of a known color */ - //% weight=84 + //% blockId="neopixel_colors" block="%color" //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" + //% weight=84 //% group="colors" - //% group.loc.de=" Farben" + //% group.loc.de="Farben" export function colors(color: NeoPixelColors): number { return color; } From dfeaf4de7960653e8394256bb4df32eb0f2eb38a Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:32:43 +0100 Subject: [PATCH 236/253] order changed --- StartbitV2.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index cf2b5fa..e4ecfb0 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -996,7 +996,7 @@ namespace informatiktheater { * Der Bildschirminhalt wird gelöscht und ``anzeigen`` muss nicht aufgerufen werden */ //% blockId="Matrix_scrollText" block="%matrix Text: %text|Geschwindigkeit (0-200): %speed|Farbe: %colour" - //% weight=35 + //% weight=20 //% subcategory=Matrix //% colour.shadow=neopixel_colors //% speed.min=1 speed.max=200 speed.defl=50 @@ -1024,8 +1024,8 @@ namespace informatiktheater { * Es muss anschliessend ``anzeigen`` aufgerufen werden. */ //% blockId="Matrix_text" block="%matrix Text: %text|Position: %x_offset|Farbe: %colour" - //% weight=35 - //% subcategory=Matrix + //% + //% subcategory=Matrix weight=21 //% colour.shadow=neopixel_colors //% x_offset.defl=0 x_offset.min=0 x_offset.max=32 //% group="Features" weight=2 From 0c83cd5630165c482005e1c7610a20140503a4e0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:43:06 +0100 Subject: [PATCH 237/253] Update StartbitV2.ts --- StartbitV2.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index e4ecfb0..d28d6be 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -741,9 +741,10 @@ namespace informatiktheater { //% red.defl=255 red.min=0 red.max=255 //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 + //% weight=84 //% subcategory="Stripe" - //% group="colors" weight=84 - //% group.loc.de=" Farben" + //% group="Farben" + //% group.loc.de="Farben" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); } @@ -758,7 +759,8 @@ namespace informatiktheater { //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" - //% group="colors" weight=85 + //% weight=85 + //% group="Farben" //% group.loc.de="Farben" export function hsv_picker(hue: number): number { From 51503fea8ad2c0b4856121d2982f78c2bc5c709d Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:45:18 +0100 Subject: [PATCH 238/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d28d6be..2966e81 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -777,7 +777,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" //% weight=84 - //% group="colors" + //% group="Farben" //% group.loc.de="Farben" export function colors(color: NeoPixelColors): number { return color; From 9f358aa72fa1a355bd980a3ff3ab6045e2eb7f87 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:49:16 +0100 Subject: [PATCH 239/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 2966e81..ac9f454 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -272,7 +272,7 @@ namespace informatiktheater { //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" - //% group="colors" + //% group="Farben" //% group.loc.de="Farben" export function __colorNumberPicker(value: number) { return value; From 1501fa78e89468a348bea7d8f51bf9904abbada2 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:55:19 +0100 Subject: [PATCH 240/253] Update StartbitV2.ts --- StartbitV2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ac9f454..d368b7d 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1315,7 +1315,7 @@ namespace informatiktheater { } export enum startbit_ultrasonicPort { - port1 = 0x01, + P2/P1 = 0x01, port2 = 0x02, } @@ -1771,7 +1771,7 @@ namespace informatiktheater { //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { - case startbit_ultrasonicPort.port1: + case startbit_ultrasonicPort.P2/P1: echoPin = DigitalPin.P2; trigPin = DigitalPin.P1; break; @@ -1884,7 +1884,7 @@ namespace informatiktheater { } export enum startbit_trittmattePort { - port1 = 0x01, + P2/P1 = 0x01, port2 = 0x02, port3 = 0x03, } @@ -1904,7 +1904,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P2/P1: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: @@ -1938,7 +1938,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P2/P1: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: @@ -1975,7 +1975,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P2/P1: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: From 0f405e3fd2415b412a703db4a449805c980d7de1 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:02:14 +0100 Subject: [PATCH 241/253] changed Sensoren port1 - 3 replaced with P2P1 P14P13. P16 --- StartbitV2.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d368b7d..1ca1814 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1315,8 +1315,8 @@ namespace informatiktheater { } export enum startbit_ultrasonicPort { - P2/P1 = 0x01, - port2 = 0x02, + P2P1 = 0x01, + P14P13 = 0x02, } export function startbit_Init() { @@ -1771,11 +1771,11 @@ namespace informatiktheater { //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { - case startbit_ultrasonicPort.P2/P1: + case startbit_ultrasonicPort.P2P1: echoPin = DigitalPin.P2; trigPin = DigitalPin.P1; break; - case startbit_ultrasonicPort.port2: + case startbit_ultrasonicPort.P14P13: echoPin = DigitalPin.P14; trigPin = DigitalPin.P13; break; @@ -1884,9 +1884,9 @@ namespace informatiktheater { } export enum startbit_trittmattePort { - P2/P1 = 0x01, - port2 = 0x02, - port3 = 0x03, + P2P1 = 0x01, + P14P13 = 0x02, + P16 = 0x03, } let debounce_time = 150; // debounce for pin input events in [ms] @@ -1904,13 +1904,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2/P1: + case startbit_trittmattePort.P2P1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14P13: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; } @@ -1938,13 +1938,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2/P1: + case startbit_trittmattePort.P2P1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14P13: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; } @@ -1975,13 +1975,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2/P1: + case startbit_trittmattePort.P2P1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14P13: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; } From c8c70ae02ed7b5ad88387dd4860786a8a4674309 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:15:34 +0100 Subject: [PATCH 242/253] back --- StartbitV2.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 1ca1814..232ce00 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1315,8 +1315,8 @@ namespace informatiktheater { } export enum startbit_ultrasonicPort { - P2P1 = 0x01, - P14P13 = 0x02, + port1 = 0x01, + port2 = 0x02, } export function startbit_Init() { @@ -1771,11 +1771,11 @@ namespace informatiktheater { //Silvan: I don't think we should switch from port to pins here (one would have to define two pins instead of a single port) export function ultrasonic_init(port: startbit_ultrasonicPort) { switch (port) { - case startbit_ultrasonicPort.P2P1: + case startbit_ultrasonicPort.port1: echoPin = DigitalPin.P2; trigPin = DigitalPin.P1; break; - case startbit_ultrasonicPort.P14P13: + case startbit_ultrasonicPort.port2: echoPin = DigitalPin.P14; trigPin = DigitalPin.P13; break; @@ -1884,9 +1884,9 @@ namespace informatiktheater { } export enum startbit_trittmattePort { - P2P1 = 0x01, - P14P13 = 0x02, - P16 = 0x03, + port1 = 0x01, + port2 = 0x02, + port3 = 0x03, } let debounce_time = 150; // debounce for pin input events in [ms] @@ -1904,13 +1904,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2P1: + case startbit_trittmattePort.port1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.P14P13: + case startbit_trittmattePort.port2: pin = DigitalPin.P14; break; - case startbit_trittmattePort.P16: + case startbit_trittmattePort.port3: pin = DigitalPin.P16; break; } @@ -1938,7 +1938,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2P1: + case startbit_trittmattePort.port1: pin = DigitalPin.P2; break; case startbit_trittmattePort.P14P13: @@ -1975,13 +1975,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P2P1: + case startbit_trittmattePort.port1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.P14P13: + case startbit_trittmattePort.port2: pin = DigitalPin.P14; break; - case startbit_trittmattePort.P16: + case startbit_trittmattePort.port3: pin = DigitalPin.P16; break; } From aeebc3c411d368acd98ee264e233d476a983e657 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 28 Mar 2024 23:20:32 +0100 Subject: [PATCH 243/253] Update StartbitV2.ts --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 232ce00..ac9f454 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1941,10 +1941,10 @@ namespace informatiktheater { case startbit_trittmattePort.port1: pin = DigitalPin.P2; break; - case startbit_trittmattePort.P14P13: + case startbit_trittmattePort.port2: pin = DigitalPin.P14; break; - case startbit_trittmattePort.P16: + case startbit_trittmattePort.port3: pin = DigitalPin.P16; break; } From 6d44e8a9f7ea13136e0880ddb6c2250adc9fbbd0 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:37:43 +0200 Subject: [PATCH 244/253] Update StartbitV2.ts --- StartbitV2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ac9f454..bdf5e28 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -268,7 +268,8 @@ namespace informatiktheater { //% blockId=brightColorNumberPicker block="%value" //% shim=TD_ID colorSecondary="#FFFFFF" //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true - //% value.defl='#ff0000' weight=29 + //% value.defl='#ff0000' + //% weight=100 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" From 2a43e8b1de1fdcddfc3a1fd6aa27d00f43797ebe Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:36:39 +0200 Subject: [PATCH 245/253] Update StartbitV2.ts order --- StartbitV2.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index bdf5e28..d66d7d4 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -269,7 +269,7 @@ namespace informatiktheater { //% shim=TD_ID colorSecondary="#FFFFFF" //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true //% value.defl='#ff0000' - //% weight=100 + //% weight=8 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" @@ -735,14 +735,13 @@ namespace informatiktheater { * @param g green channel * @param b blue channel */ - //% weight=86 + //% weight=4 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" //% block.loc.de="rot %red|grün %green|blau %blue" //% jsdoc.loc.de="Erstellt eine RGB-Farbe" //% red.defl=255 red.min=0 red.max=255 //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 - //% weight=84 //% subcategory="Stripe" //% group="Farben" //% group.loc.de="Farben" @@ -760,7 +759,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" - //% weight=85 + //% weight=3 //% group="Farben" //% group.loc.de="Farben" @@ -777,7 +776,7 @@ namespace informatiktheater { //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" - //% weight=84 + //% weight=2 //% group="Farben" //% group.loc.de="Farben" export function colors(color: NeoPixelColors): number { From ba683fedeb2f2c5db3d161e621fbd5a4e615776a Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:40:27 +0200 Subject: [PATCH 246/253] Update StartbitV2.ts --- StartbitV2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d66d7d4..af8c837 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1762,7 +1762,7 @@ namespace informatiktheater { let echoPin: DigitalPin; let trigPin: DigitalPin; - //% weight=16 + //% weight=17 //% blockId=ultrasonic_init //% block="initialize ultrasonic |%pin" //% block.loc.de="initialisiere Ultraschall|%pin" @@ -1786,7 +1786,7 @@ namespace informatiktheater { /** * Get the distance of ultrasonic detection to the obstacle */ - //% weight=17 + //% weight=16 //% blockId=startbit_ultrasonic //% block="get ultrasonic |distancse (cm)" //% block.loc.de="Ultraschall|Distanz (cm)" From cce9e642e7e13ab966fb4dd4160552c351901ddc Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:48:47 +0200 Subject: [PATCH 247/253] Update StartbitV2.ts --- StartbitV2.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/StartbitV2.ts b/StartbitV2.ts index af8c837..41b1d31 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1455,12 +1455,14 @@ namespace informatiktheater { //% weight=100 //% blockId=setServo //% block="set servo motor %index| angle (°) %angle| duration (ms) %duration" + //% angle.shadow="protractorPicker" //% block.loc.de="setze Servomotor %index| auf Winkel (0 - 180°) %angle|für Dauer (ms) %duration" //% angle.min=0 angle.max=180 //% index.defl=1 //% duration.shadow=timePicker //% inlineInputMode=inline //% subcategory=Servo/Motor + //% group=Servo export function setPwmServo( index: ServoIndex = 1, angle: number, From 4405289355329e8653bc2591e42239a8e69c8740 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:56:11 +0200 Subject: [PATCH 248/253] Update StartbitV2.ts --- StartbitV2.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 41b1d31..d2c62fb 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -273,7 +273,7 @@ namespace informatiktheater { //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" - //% group="Farben" + //% group="colors" //% group.loc.de="Farben" export function __colorNumberPicker(value: number) { return value; @@ -743,7 +743,7 @@ namespace informatiktheater { //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 //% subcategory="Stripe" - //% group="Farben" + //% group="colors" //% group.loc.de="Farben" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); @@ -759,8 +759,8 @@ namespace informatiktheater { //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" - //% weight=3 - //% group="Farben" + //% weight=5 + //% group="colors" //% group.loc.de="Farben" export function hsv_picker(hue: number): number { @@ -776,8 +776,8 @@ namespace informatiktheater { //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" - //% weight=2 - //% group="Farben" + //% weight=3 + //% group="colors" //% group.loc.de="Farben" export function colors(color: NeoPixelColors): number { return color; From f3b040236a4a6e391e3ec3f1c5365cbe41d75d99 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:27:38 +0200 Subject: [PATCH 249/253] Update StartbitV2.ts --- StartbitV2.ts | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index d2c62fb..ccee293 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -269,12 +269,10 @@ namespace informatiktheater { //% shim=TD_ID colorSecondary="#FFFFFF" //% value.fieldEditor="colornumber" value.fieldOptions.decompileLiterals=true //% value.defl='#ff0000' - //% weight=8 //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" - //% group="colors" - //% group.loc.de="Farben" + //% group="Farben" export function __colorNumberPicker(value: number) { return value; } @@ -593,7 +591,7 @@ namespace informatiktheater { //% strip.defl=strip //% weight=40 //% parts="neopixel" - //% subcategory=Stripe + //% subcategory="Stripe" //% group="Kontrolle" shift(offset: number = 1): void { offset = offset >> 0; @@ -616,7 +614,7 @@ namespace informatiktheater { //% strip.defl=strip //% weight=39 //% parts="neopixel" - //% subcategory=Stripe + //% subcategory="Stripe" //% group="Kontrolle" rotate(offset: number = 1): void { offset = offset >> 0; @@ -743,8 +741,7 @@ namespace informatiktheater { //% blue.defl=255 blue.min=0 blue.max=255 //% green.defl=255 green.min=0 green.max=255 //% subcategory="Stripe" - //% group="colors" - //% group.loc.de="Farben" + //% group="Farben" export function rgb(red: number, green: number, blue: number): number { return packRGB(red, green, blue); } @@ -760,8 +757,7 @@ namespace informatiktheater { //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" //% weight=5 - //% group="colors" - //% group.loc.de="Farben" + //% group="Farben" export function hsv_picker(hue: number): number { let mapped_hue = (hue * 360) / 255; @@ -777,8 +773,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" //% weight=3 - //% group="colors" - //% group.loc.de="Farben" + //% group="Farben" export function colors(color: NeoPixelColors): number { return color; } @@ -1196,8 +1191,8 @@ namespace informatiktheater { */ //% blockId="color_for_led_16" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8$c_9$c_10$c_11$c_12$c_13$c_14$c_15$c_16" //% subcategory=Matrix - //% group="colors" weight=49 - //% group.loc.de="Farben" + //% group="Farben" + //% weight=49 //% c_1.shadow="brightColorNumberPicker" //% c_2.shadow="brightColorNumberPicker" //% c_3.shadow="brightColorNumberPicker" @@ -1241,8 +1236,8 @@ namespace informatiktheater { */ //% blockId="color_for_led_32" block="$c_1|$c_2|$c_3|$c_4|$c_5|$c_6|$c_7|$c_8|$c_9|$c_10|$c_11|$c_12|$c_13|$c_14|$c_15|$c_16|$c_17|$c_18|$c_19|$c_20|$c_21|$c_22|$c_23|$c_24|$c_25|$c_26|$c_27|$c_28|$c_29|$c_30|$c_31|$c_32|" //% subcategory=Matrix - //% group="colors" weight=47 - //% group.loc.de="Farben" + //% group="Farben" + //% weight=47 //% c_1.shadow="brightColorNumberPicker" //% c_2.shadow="brightColorNumberPicker" //% c_3.shadow="brightColorNumberPicker" From c6c2ebc8848acfdf7622d468e21f2c493419cafa Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:35:48 +0200 Subject: [PATCH 250/253] Update StartbitV2.ts --- StartbitV2.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index ccee293..5d8b4e6 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -272,6 +272,7 @@ namespace informatiktheater { //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' //% subcategory="Stripe" + //% weight=77 //% group="Farben" export function __colorNumberPicker(value: number) { return value; @@ -733,7 +734,7 @@ namespace informatiktheater { * @param g green channel * @param b blue channel */ - //% weight=4 + //% weight=70 //% blockId="neopixel_rgb" block="red %red|green %green|blue %blue" //% block.loc.de="rot %red|grün %green|blau %blue" //% jsdoc.loc.de="Erstellt eine RGB-Farbe" @@ -756,7 +757,7 @@ namespace informatiktheater { //% jsdoc.loc.de="Erstellt eine Farbe" //% hue.shadow="colorWheelHsvPicker" //% subcategory="Stripe" - //% weight=5 + //% weight=80 //% group="Farben" export function hsv_picker(hue: number): number { @@ -772,7 +773,7 @@ namespace informatiktheater { //% block.loc.de="%color" //% jsdoc.loc.de="Bekannte RGB-Farben" //% subcategory="Stripe" - //% weight=3 + //% weight=90 //% group="Farben" export function colors(color: NeoPixelColors): number { return color; From 77f045f8805e03ed24fe254ec8321aad6eef3920 Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:38:19 +0200 Subject: [PATCH 251/253] Update StartbitV2.ts --- StartbitV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 5d8b4e6..8fa9a57 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -271,7 +271,7 @@ namespace informatiktheater { //% value.defl='#ff0000' //% value.fieldOptions.colours='["#000000","#ff0000","#ffa500","#ffff00","#00ff00","#0000ff","#00ffff","#ff00ff","#8a2be2","#ffffff"]' //% value.fieldOptions.columns=5 value.fieldOptions.className='rgbColorPicker' - //% subcategory="Stripe" + //% subcategory="Matrix" //% weight=77 //% group="Farben" export function __colorNumberPicker(value: number) { From 36ef398d4485287df0eb37975fe3137819eb7f2b Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:26:49 +0100 Subject: [PATCH 252/253] Update StartbitV2.ts --- StartbitV2.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 8fa9a57..345a1b7 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1882,7 +1882,7 @@ namespace informatiktheater { } export enum startbit_trittmattePort { - port1 = 0x01, + P2 = 0x01, port2 = 0x02, port3 = 0x03, } @@ -1902,7 +1902,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P1_P2: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: @@ -1936,7 +1936,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P2: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: @@ -1973,7 +1973,7 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.port1: + case startbit_trittmattePort.P2: pin = DigitalPin.P2; break; case startbit_trittmattePort.port2: From b7b0a14cfbd1a14a35f58114cf9e5850090dd82d Mon Sep 17 00:00:00 2001 From: Zauberhut <49160827+Zauberhut@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:35:44 +0100 Subject: [PATCH 253/253] Update StartbitV2.ts --- StartbitV2.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/StartbitV2.ts b/StartbitV2.ts index 345a1b7..fbfa17a 100644 --- a/StartbitV2.ts +++ b/StartbitV2.ts @@ -1883,8 +1883,8 @@ namespace informatiktheater { export enum startbit_trittmattePort { P2 = 0x01, - port2 = 0x02, - port3 = 0x03, + P14 = 0x02, + P16 = 0x03, } let debounce_time = 150; // debounce for pin input events in [ms] @@ -1902,13 +1902,13 @@ namespace informatiktheater { ): void { let pin: DigitalPin; switch (port) { - case startbit_trittmattePort.P1_P2: + case startbit_trittmattePort.P2: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; } @@ -1939,10 +1939,10 @@ namespace informatiktheater { case startbit_trittmattePort.P2: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; } @@ -1976,10 +1976,10 @@ namespace informatiktheater { case startbit_trittmattePort.P2: pin = DigitalPin.P2; break; - case startbit_trittmattePort.port2: + case startbit_trittmattePort.P14: pin = DigitalPin.P14; break; - case startbit_trittmattePort.port3: + case startbit_trittmattePort.P16: pin = DigitalPin.P16; break; }