diff --git a/battery.ts b/battery.ts new file mode 100644 index 0000000..69602a5 --- /dev/null +++ b/battery.ts @@ -0,0 +1,26 @@ +/******************************************************************************* + * Functions for SUMO:BIT battery input + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + +namespace sumobit { + + /** + * Return the current battery voltage. + */ + //% group="Battery" + //% weight=49 + //% blockGap=8 + //% blockId=sumobit_read_VIN + //% block="battery voltage" + export function readBatteryValue(): number { + let highByte: number; + let lowByte: number; + highByte = sumobit.i2cRead(REG_ADD_VIN_HIGH); + lowByte = sumobit.i2cRead(REG_ADD_VIN_LOW); + return ((highByte << 8) | lowByte) / 100; + } +} diff --git a/edge.ts b/edge.ts new file mode 100644 index 0000000..090fc99 --- /dev/null +++ b/edge.ts @@ -0,0 +1,106 @@ +/******************************************************************************* + * Functions for SUMO:BIT edge sensors + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + +// Default pin. +const EDGE_R_PIN = AnalogPin.P0; +const EDGE_L_PIN = AnalogPin.P1; + +// Event source. +const EDGE_SENSOR_EVENT_SOURCE = 0x03; + +// Edge sensor side +enum EdgeSide { + + //% block="right" + Right = 0, + //% block="left" + Left = 1, + + //% block="both" + Both = 1000 +} + +// Comparison type. +enum EdgeCompareType { + //% block=">" + MoreThan = 0, + + //% block="<" + LessThan = 1 +} + +namespace sumobit { + + /** + * Return the right edge sensor value (0-1023). + */ + //% group="Edge Sensors" + //% weight=79 + //% blockGap=8 + //% blockId=sumobit_read_edge_R_value + //% block="right edge sensor" + export function readEdgeRValue(): number { + return pins.analogReadPin(EDGE_R_PIN); + } + + /** + * Return the left edge sensor value (0-1023). + */ + //% group="Edge Sensors" + //% weight=78 + //% blockGap=8 + //% blockId=sumobit_read_edge_L_value + //% block="left edge sensor" + export function readEdgeLValue(): number { + return pins.analogReadPin(EDGE_L_PIN); + } + + + /** + * Compare the edge sensor(s) value (0-1023) with certain value and return true if condition is meet. + * @param EdgeSide Which side of edge sensors are to compare to. eg: 0 + * @param compareType More than or less than. eg: 0 + * @param threshold The value to compare with. eg: 512 + */ + //% group="Edge Sensors" + //% weight=77 + //% blockGap=40 + //% blockId=sumobit_compare_edge_value + //% block="%side edge sensor %compareType %threshold" + //% threshold.min=0 threshold.max=1023 + export function compareEdge(side: EdgeSide, compareType: EdgeCompareType, threshold: number,): boolean { + + let result = false; + let R = readEdgeRValue(); + let L = readEdgeLValue(); + + + switch (side) { + case EdgeSide.Right: + if ((R > threshold && EdgeCompareType.MoreThan) || (R < threshold && EdgeCompareType.LessThan)) { + result = true; + } + break; + + case EdgeSide.Left: + if ((L > threshold && EdgeCompareType.MoreThan) || (L < threshold && EdgeCompareType.LessThan)) { + result = true; + } + break; + + case EdgeSide.Both: + if (((R > threshold && L > threshold) && EdgeCompareType.MoreThan) || ((R > threshold && L > threshold) && EdgeCompareType.LessThan)) { + result = true; + } + break; + } + + return result; + + } +} \ No newline at end of file diff --git a/main.ts b/main.ts index ee54a1b..3a4c1b3 100644 --- a/main.ts +++ b/main.ts @@ -1,3 +1,110 @@ -basic.forever(function () { - -}) +// I2C Adress +const I2C_ADDRESS = 0x09; + +// Register addresses. +const REG_ADD_REVISION = 0; +const REG_ADD_SRV1_POS = 1; +const REG_ADD_SRV1_SPEED = 2; +const REG_ADD_SRV2_POS = 3; +const REG_ADD_SRV2_SPEED = 4; +const REG_SERVO_R1 = 5; +const REG_SERVO_R2 = 6; +const REG_SERVO_R3 = 7; +const REG_SERVO_R4 = 8; +const REG_ADD_PWM1 = 9; +const REG_ADD_DIR1 = 10; +const REG_ADD_ACCEL1 = 11; +const REG_ADD_PWM2 = 12; +const REG_ADD_DIR2 = 13; +const REG_ADD_ACCEL2 = 14; +const REG_MOTOR_R1 = 15; +const REG_MOTOR_R2 = 16; +const REG_MOTOR_R3 = 17; +const REG_MOTOR_R4 = 18; +const REG_ADD_R0 = 19; +const REG_ADD_G0 = 20; +const REG_ADD_B0 = 21; +const REG_ADD_R1 = 22; +const REG_ADD_G1 = 23; +const REG_ADD_B1 = 24; +const REG_ADD_AN1_HIGH = 25; +const REG_ADD_AN1_LOW = 26; +const REG_ADD_AN2_HIGH = 27; +const REG_ADD_AN2_LOW = 28; +const REG_CURRENT_R1 = 29; +const REG_CURRENT_R2 = 30; +const REG_ADD_VIN_HIGH = 31; +const REG_ADD_VIN_LOW = 32; +const REG_VIN_R1 = 33; +const REG_VIN_R2 = 34; +const REG_ADD_DIP = 35; +const REG_ADD_RESET = 36; + + + +/** +* Blocks for SUMO:BIT. +*/ + +//% weight=10 color=#ff8000 icon="\uf091" block="SUMO:BIT" +//% groups=['DC Motors', 'Servos' , 'Mode', 'Motor Current','Opponent Sensors' , 'Edge Sensors', 'RGB LED'] +namespace sumobit { + + // Stop all motor at start + brakeMotor(MotorChannel.MR); + brakeMotor(MotorChannel.ML); + + // Disable the servos. + disableServo(ServoChannel.S1); + disableServo(ServoChannel.S2); + + + /** + * Limit the range of a number. + * @param value The number we want to limit. + * @param min Minimum value of the number. + * @param max Maximum value of the number. + */ + //% blockHidden=true + //% blockId=sumobit_limit + export function limit(value: number, min: number, max: number): number { + if (value < min) { + value = min; + } + else if (value > max) { + value = max; + } + return value; + } + + + /** + * I2C read from the register of RP2040. + * @param register Register address. + */ + //% blockHidden=true + //% blockId=sumobit_i2c_read + export function i2cRead(register: number): number { + let value = 0; + pins.i2cWriteNumber(I2C_ADDRESS, register, NumberFormat.UInt8LE, true); + value = pins.i2cReadNumber(I2C_ADDRESS, NumberFormat.UInt8LE); + return value; + } + + + /** + * I2C write to the register of RP2040. + * @param register Register address. + * @param data Data to write. + */ + //% blockHidden=true + //% blockId=sumobit_i2c_write + export function i2cWrite(register: number, data: number): void { + let buffer = pins.createBuffer(2); + buffer[0] = register; + buffer[1] = data; + pins.i2cWriteBuffer(I2C_ADDRESS, buffer); + } + + +} \ No newline at end of file diff --git a/mode.ts b/mode.ts new file mode 100644 index 0000000..9524bfd --- /dev/null +++ b/mode.ts @@ -0,0 +1,115 @@ +/******************************************************************************* + * Functions for sumo:bit mode. + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ +const MODE_EVENT_SOURCE = 0x01; + +namespace sumobit { + + let bgFunctionCreated = false; + + // Event type. + let eventType = 0; + + // Array for mode value. + let modevalueArray: number[] = []; + + // Array for old compare result. + let oldCompareResult: boolean[] = []; + + + /** + * Return the current mode number(0-15). + */ + //% group="Mode" + //% weight=69 + //% blockGap=8 + //% blockId=sumobit_read_mode_value + //% block="mode" + export function readModeValue(): number { + return sumobit.i2cRead(REG_ADD_DIP); + } + + /** + * Check the current mode number (0-15) and returns the result if true. + * @param modevalue The current DIP position. eg: 7 + */ + //% group="Mode" + //% weight=68 + //% blockGap=40 + //% blockId=sumobit_check_mode_value + //% block="mode %modevalue" + //% modevalue.min=0 modevalue.max=15 + export function checkMode(modevalue: number): boolean { + let result = false; + + if (readModeValue() === modevalue) { + result = true; + } + + return result; + } + + /** + * Check current mode value and do something when true. + * @param modevalue The current mode value. eg: 7 + * @param handler Code to run when the event is raised. + */ + //% group="Mode" + //% weight=67 + //% blockGap=8 + //% blockId=sumobit_mode_event + //% block="on mode value %modevalue" + //% modevalue.min=0 modevalue.max=15 + //% blockHidden=true + export function onModeEvent(modevalue: number, handler: Action): void { + // Use a new event type everytime a new event is create. + eventType++; + + // Add the event info to the arrays. + modevalueArray.push(modevalue); + + // Create a placeholder for the old compare result. + oldCompareResult.push(false); + + // Register the event. + control.onEvent(MODE_EVENT_SOURCE, eventType, handler); + + // Create a function in background if haven't done so. + // This function will check for pot value and raise the event if the condition is met. + if (bgFunctionCreated == false) { + control.inBackground(function () { + + while (true) { + // Loop for all the event created. + for (let i = 0; i < eventType; i++) { + + // Check if the condition is met. + if (checkMode(modevalueArray[i]) == true) { + // Raise the event if the compare result changed from false to true. + if (oldCompareResult[i] == false) { + control.raiseEvent(MODE_EVENT_SOURCE, i + 1); + } + + // Save old compare result. + oldCompareResult[i] = true; + } + else { + // Save old compare result. + oldCompareResult[i] = false; + } + basic.pause(20) + } + } + + }); + + bgFunctionCreated = true; + } + + } + +} diff --git a/motor.ts b/motor.ts new file mode 100644 index 0000000..4637fce --- /dev/null +++ b/motor.ts @@ -0,0 +1,137 @@ +/******************************************************************************* + * Functions for SUMO:BIT motor control + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + + + +// Motor direction. +enum MotorDirection { + //% block="forward" + Forward = 0, + + //% block="backward" + Backward = 1 +}; + +namespace sumobit { + +// Motor channel. +export enum MotorChannel { + + //% block="right" + MR = 0, + + //% block="left" + ML = 1, + + //% block="both" + All = 1000, +}; + + + /** + * Stop motor + * @param motor Motorchannel eg: Motor.M1, Motor.M2 + */ + //% group="DC Motors" + //% weight=98 + //% blockGap=8 + //% blockId=sumobit_brake_motor + //% block="brake motor %motor" + export function brakeMotor(motor: MotorChannel): void { + switch (motor) { + case MotorChannel.MR: + sumobit.i2cWrite(REG_ADD_PWM1, 0); + sumobit.i2cWrite(REG_ADD_DIR1, 0); + break; + + case MotorChannel.ML: + sumobit.i2cWrite(REG_ADD_PWM2, 0); + sumobit.i2cWrite(REG_ADD_DIR2, 0); + break; + + case MotorChannel.All: + sumobit.i2cWrite(REG_ADD_PWM1, 0); + sumobit.i2cWrite(REG_ADD_DIR1, 0); + sumobit.i2cWrite(REG_ADD_PWM2, 0); + sumobit.i2cWrite(REG_ADD_DIR2, 0); + break; + } + } + + + /** + * Run the motor forward or backward (Speed = 0-255). + * @param motor Motor channel. + * @param direction Motor direction. + * @param speed Motor speed (0-255). eg: 128 + * @param accelaration Acceleration factor (0-9). eg: 0 + */ + //% group="DC Motors" + //% weight=99 + //% blockGap=8 + //% blockId=sumobit_run_motor + //% accel.fieldOptions.label="Acceleration Factor" + //% block="run %motor motor %direction at %speed speed || with %accelaration acceleration factor" + //% inlineInputMode=inline + //% speed.min=0 speed.max=255 + //% accelaration.min=0 accelaration.max=9 + //% expandableArgumentMode="enabled" + + export function runMotor(motor: MotorChannel, direction: MotorDirection, speed: number, accelaration: number = 0): void { + speed = sumobit.limit(speed, 0, 255); + accelaration = sumobit.limit(accelaration, 0, 9); + switch (motor) { + case MotorChannel.MR: + if (direction == MotorDirection.Forward) { + sumobit.i2cWrite(REG_ADD_PWM1, speed); + sumobit.i2cWrite(REG_ADD_DIR1, 0); + sumobit.i2cWrite(REG_ADD_ACCEL1, accelaration); + } + else { + sumobit.i2cWrite(REG_ADD_PWM1, speed); + sumobit.i2cWrite(REG_ADD_DIR1, 1); + sumobit.i2cWrite(REG_ADD_ACCEL1, accelaration); + } + break; + + case MotorChannel.ML: + if (direction == MotorDirection.Forward) { + sumobit.i2cWrite(REG_ADD_PWM2, speed); + sumobit.i2cWrite(REG_ADD_DIR2, 0); + sumobit.i2cWrite(REG_ADD_ACCEL2, accelaration); + } + else { + sumobit.i2cWrite(REG_ADD_PWM2, speed); + sumobit.i2cWrite(REG_ADD_DIR2, 1); + sumobit.i2cWrite(REG_ADD_ACCEL2, accelaration); + } + break; + + case MotorChannel.All: + if (direction == MotorDirection.Forward) { + sumobit.i2cWrite(REG_ADD_PWM1, speed); + sumobit.i2cWrite(REG_ADD_DIR1, 0); + sumobit.i2cWrite(REG_ADD_ACCEL1, accelaration); + sumobit.i2cWrite(REG_ADD_PWM2, speed); + sumobit.i2cWrite(REG_ADD_DIR2, 0); + sumobit.i2cWrite(REG_ADD_ACCEL2, accelaration); + } + else { + sumobit.i2cWrite(REG_ADD_PWM1, speed); + sumobit.i2cWrite(REG_ADD_DIR1, 1); + sumobit.i2cWrite(REG_ADD_ACCEL1, accelaration); + sumobit.i2cWrite(REG_ADD_PWM2, speed); + sumobit.i2cWrite(REG_ADD_DIR2, 1); + sumobit.i2cWrite(REG_ADD_ACCEL2, accelaration); + } + break; + } + } + + +} diff --git a/motorcurrent.ts b/motorcurrent.ts new file mode 100644 index 0000000..b360624 --- /dev/null +++ b/motorcurrent.ts @@ -0,0 +1,196 @@ +/******************************************************************************* + * Functions for sumo:bit motor current measurement. + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + + +const MOTORCURRENT_EVENT_SOURCE = 0x02; + +// Motor selection +enum MotorSelect { + M1 = 0, + M2 = 1, + + //% block="M1 and M2" + AND = 1000 + +} + +// Motor selection option used in the comparision function +enum CompareSelect { + M1 = 0, + M2 = 1, + + //% block="M1 and M2" + AND = 1000 + +} + +// Comparison type +enum CompareType { + //% block=">" + MoreThan = 0, + + //% block="<" + LessThan = 1 +}; + + +namespace sumobit { + + // + let bgFunctionCreated = false; + + // Event type. + let eventType = 0; + + // Array for mode value. + let thresholdsArray: number[] = []; + let compareTypesArray: CompareType[] = []; + let motorArray: CompareSelect[] = []; + + // Array for old compare result. + let oldCompareResult: boolean[] = []; + + + /** + * Return Right Motor current value. + */ + //% group="Motor Current" + //% weight=59 + //% blockGap=8 + //% blockId=sumobit_read_m1_current_value + //% block="right motor current" + export function readM1CurrentValue(): number { + let highByte: number; + let lowByte: number; + highByte = sumobit.i2cRead(REG_ADD_AN1_HIGH); + lowByte = sumobit.i2cRead(REG_ADD_AN1_LOW); + return ((highByte << 8) | lowByte) / 100; + } + + /** + * Return motor 2 current value. + */ + //% group="Motor Current" + //% weight=58 + //% blockGap=8 + //% blockId=sumobit_read_m2_current_value + //% block="left motor current" + export function readM2CurrentValue(): number { + let highByte: number; + let lowByte: number; + highByte = sumobit.i2cRead(REG_ADD_AN2_HIGH); + lowByte = sumobit.i2cRead(REG_ADD_AN2_LOW); + return ((highByte << 8) | lowByte) / 100; + } + + + + /** + * Compare the motor current value (0.00-20.00) and returns the result (true/false). + * @param threshold The current DIP position. eg: 14.00 + */ + //% group="Motor Current" + //% weight=57 + //% blockGap=40 + //% blockId=sumobit_compare_current_value + //% block="%motor current %compareType %threshold" + //% threshold.min=0.00 threshold.max=15.00 REG_ADD_AN1_HIGH + //% blockHidden=true + export function compareCurrent(motor: CompareSelect, compareType: CompareType, threshold: number,): boolean { + let result = false; + let a = readM1CurrentValue(); + let b = readM2CurrentValue(); + + + switch (motor) { + case CompareSelect.M1: + if ((a > threshold && CompareType.MoreThan) || (a < threshold && CompareType.LessThan)) { + result = true; + } + break; + + case CompareSelect.M2: + if ((b > threshold && CompareType.MoreThan) || (b < threshold && CompareType.LessThan)) { + result = true; + } + break; + + case CompareSelect.AND: + if (((a > threshold && b > threshold) && CompareType.MoreThan) || ((a > threshold && b > threshold) && CompareType.LessThan)) { + result = true; + } + break; + } + + return result; + } + + + /** + * Compare the motor current value with a certain value and do something when true. + * @param motor M1, M2 or Both. + * @param compareType More than or less than. + * @param threshold The value to compare with. eg: 7.00 + * @param handler Code to run when the event is raised. + */ + //% group="Motor Current" + //% weight=56 + //% blockGap=40 + //% blockId=sumobit_motorcurrent_event + //% block="on %motor current %compareType %threshold" + //% threshold.min=0.00 threshold.max=15.00 + export function onEvent(motor: CompareSelect, compareType: CompareType, threshold: number, handler: Action): void { + // Use a new event type everytime a new event is create. + eventType++; + + // Add the event info to the arrays. + motorArray.push(motor); + compareTypesArray.push(compareType); + thresholdsArray.push(threshold); + + // Create a placeholder for the old compare result. + oldCompareResult.push(false); + + // Register the event. + control.onEvent(MOTORCURRENT_EVENT_SOURCE, eventType, handler); + + // Create a function in background if haven't done so. + // This function will check for pot value and raise the event if the condition is met. + if (bgFunctionCreated == false) { + control.inBackground(function () { + + while (true) { + // Loop for all the event created. + for (let i = 0; i < eventType; i++) { + + // Check if the condition is met. + if (compareCurrent(motorArray[i], compareTypesArray[i], thresholdsArray[i]) == true) { + // Raise the event if the compare result changed from false to true. + if (oldCompareResult[i] == false) { + control.raiseEvent(MOTORCURRENT_EVENT_SOURCE, i + 1); + } + + // Save old compare result. + oldCompareResult[i] = true; + } + else { + // Save old compare result. + oldCompareResult[i] = false; + } + basic.pause(10) + } + } + + }); + + bgFunctionCreated = true; + } + + } + +} diff --git a/opponent.ts b/opponent.ts new file mode 100644 index 0000000..e7d39ac --- /dev/null +++ b/opponent.ts @@ -0,0 +1,172 @@ +/******************************************************************************* + * Functions for SUMO:BIT opponent sensors + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + +enum SensorPosition { + //% block="left" + Left2 = 0, + + //% block="front left" + Left1 = 1, + + //% block="front center" + Center = 2, + + //% block="front right" + Right1 = 3, + + //% block="right" + Right2 = 4, + + //% block="all" + All = 5, + + //% block="none" + None = 6 +} + +enum Sensor { + //% block="left" + Left2 = 0, + + //% block="front left" + Left1 = 1, + + //% block="front center" + Center = 2, + + //% block="front right" + Right1 = 3, + + //% block="right" + Right2 = 4, +} + + + + + +namespace sumobit { + + /** + * Read the opponent sensor value. + */ + //% group="Opponent Sensors" + //% weight=89 + //% blockGap=8 + //% blockId=sumobit_maker_object_read_digital + //% block="%sensor Opponent sensor" + export function OppSensorValue(sensor: Sensor): number { + + switch (sensor) { + case Sensor.Left2: + return pins.digitalReadPin(DigitalPin.P16); + case Sensor.Left1: + return pins.digitalReadPin(DigitalPin.P15);; + case Sensor.Center: + return pins.digitalReadPin(DigitalPin.P14); + case Sensor.Right1: + return pins.digitalReadPin(DigitalPin.P13); + case Sensor.Right2: + return pins.digitalReadPin(DigitalPin.P12); + + } + + } + + /** + * Return true if the opponent sensor is low (Obstacle detected). + */ + //% group="Opponent Sensors" + //% weight=88 + //% blockGap=8 + //% blockId=sumobit_maker_object_detect_opponent + //% block="%position sensor detect opponent" + //% position.fieldEditor="gridpicker" position.fieldOptions.columns=5 + export function OppSensorDetection(position: SensorPosition): boolean { + + + + let L = OppSensorValue(0); + let FL = OppSensorValue(1); + let FC = OppSensorValue(2); + let FR = OppSensorValue(3); + let R = OppSensorValue(4); + + switch (position) { + case SensorPosition.None: + if (L == 1 && FL == 1 && FC == 1 && FR == 1 && R == 1) + return true; + else return false; + + case SensorPosition.Left2: + if (L == 0 && FL == 1 && FC == 1 && FR == 1 && R == 1) + return true; + else return false; + + case SensorPosition.Left1: + if (L == 1 && FL == 0 && FC == 1 && FR == 1 && R == 1) + return true; + else return false; + + case SensorPosition.Center: + if (L == 1 && FL == 1 && FC == 0 && FR == 1 && R == 1) + return true; + else return false; + + case SensorPosition.Right1: + if (L == 1 && FL == 1 && FC == 1 && FR == 0 && R == 1) + return true; + else return false; + + case SensorPosition.Right2: + if (L == 1 && FL == 1 && FC == 1 && FR == 1 && R == 0) + return true; + else return false; + + case SensorPosition.All: + if (L == 0 && FL == 0 && FC == 0 && FR == 0 && R == 0) + return true; + else return false; + } + + return false; + } + + /** + * Opp sensor combination + */ + //% group="Opponent Sensors" + //% weight=87 + //% block="L$TogL FL$TogFL FC$TogFC FR$TogFR R$TogR" + //% TogL.shadow="toggleHighLow" TogFL.shadow="toggleHighLow" TogFC.shadow="toggleHighLow" TogFR.shadow="toggleHighLow" TogR.shadow="toggleHighLow" + //% inlineInputMode=inline + export function OppSensorCombinationBoolean(TogL: boolean, TogFL: boolean, TogFC: boolean, TogFR: boolean, TogR: boolean): boolean { + let sensorValues = [ + OppSensorValue(0), // L + OppSensorValue(1), // FL + OppSensorValue(2), // FC + OppSensorValue(3), // FR + OppSensorValue(4) // R + ]; + let referenceValues = [TogL ? 1 : 0, TogFL ? 1 : 0, TogFC ? 1 : 0, TogFR ? 1 : 0, TogR ? 1 : 0]; + + + // Compare each value in sensorValues with referenceValues + for (let i = 0; i < sensorValues.length; i++) { + if (sensorValues[i] !== referenceValues[i]) { + // If any value does not match, return false + return false; + } + } + + // If all values match, return true + return true; + } + + +} \ No newline at end of file diff --git a/pxt.json b/pxt.json index 9aace23..adc72df 100644 --- a/pxt.json +++ b/pxt.json @@ -7,9 +7,16 @@ "microphone": "*" }, "files": [ - "main.blocks", "main.ts", - "README.md" + "README.md", + "motor.ts", + "opponent.ts", + "edge.ts", + "mode.ts", + "motorcurrent.ts", + "servo.ts", + "battery.ts", + "rgb.ts" ], "testFiles": [ "test.ts" @@ -21,5 +28,5 @@ "supportedTargets": [ "microbit" ], - "preferredEditor": "blocksprj" + "preferredEditor": "tsprj" } diff --git a/rgb.ts b/rgb.ts new file mode 100644 index 0000000..df27e65 --- /dev/null +++ b/rgb.ts @@ -0,0 +1,191 @@ +/******************************************************************************* + * Functions for RGB LED. + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + +// Preset RGB Colors for the selection gridpicker +enum RgbColors { + //% 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 +} + + + +namespace sumobit { + + + /** + * Turn off all RGB pixels. + */ + //% group="RGB LED" + //% weight=29 + //% blockGap=8 + //% blockId="sumobit_clear_all_rgb_pixels" + //% block="clear all RGB pixels" + export function clearAllRgbPixels(): void { + + sumobit.i2cWrite(REG_ADD_R0, 0); + sumobit.i2cWrite(REG_ADD_G0, 0); + sumobit.i2cWrite(REG_ADD_B0, 0); + + sumobit.i2cWrite(REG_ADD_R1, 0); + sumobit.i2cWrite(REG_ADD_G1, 0); + sumobit.i2cWrite(REG_ADD_B1, 0); + + } + + + /** + * Set the brightness of the RGB pixels (0-255). + * @param brightness Pixel brightness. eg: 100 + */ + //% group="RGB LED" + //% weight=28 + //% blockGap=40 + //% blockId="sumobit_set_rgb_brightness" + //% block="set RGB pixels brightness to %brightness" + //% brightness.min=0 brightness.max=255 + //% blockHidden=true + export function setRgbBrightness(brightness: number): void { + + } + + + /** + * Show the same color on all RGB pixels. + * @param color RGB color of the pixel. + */ + //% group="RGB LED" + //% weight=27 + //% blockGap=8 + //% blockId="sumobit_set_all_rgb_pixels_color" + //% block="set all RGB pixels to %color" + //% color.shadow="colorNumberPicker" + + export function setAllRgbPixelsColor(color: number): void { + + // Extract the RGB values + let red = (color >> 16) & 0xFF; // Shift right by 16 bits and mask with 0xFF + let green = (color >> 8) & 0xFF; // Shift right by 8 bits and mask with 0xFF + let blue = color & 0xFF; + + sumobit.i2cWrite(REG_ADD_R0, red); + sumobit.i2cWrite(REG_ADD_G0, green); + sumobit.i2cWrite(REG_ADD_B0, blue); + + sumobit.i2cWrite(REG_ADD_R1, red); + sumobit.i2cWrite(REG_ADD_G1, green); + sumobit.i2cWrite(REG_ADD_B1, blue); + + } + + + /** + * Show color on individual RGB pixel. + * @param pixel The pixel number we want to change the color. + * @param color RGB color of the pixel. + */ + //% group="RGB LED" + //% weight=26 + //% blockGap=40 + //% blockId="sumobit_set_rgb_pixel_color" + //% block="set RGB pixel %pixel to %color" + //% color.shadow="colorNumberPicker" + //% pixel.min=0 pixel.max=1 + //% pixel.fieldEditor="numberdropdown" + //% pixel.fieldOptions.decompileLiterals=true + //% pixel.fieldOptions.values='0,1' + //% pixel.defl='0' + + export function setRgbPixelColor(pixel: number, color: number): void { + + + // Validate the pixel input + if (pixel < 0 || pixel > 1) { + // Use a specific error code for the pixel out of range + control.assert(false, "Error code: 1001 - Pixel must be 0 or 1"); + return; // Optionally return early to prevent further execution + } + + // Extract the RGB values + let red = (color >> 16) & 0xFF; // Shift right by 16 bits and mask with 0xFF + let green = (color >> 8) & 0xFF; // Shift right by 8 bits and mask with 0xFF + let blue = color & 0xFF; + + switch (pixel) { + case 0: + sumobit.i2cWrite(REG_ADD_R0, red); + sumobit.i2cWrite(REG_ADD_G0, green); + sumobit.i2cWrite(REG_ADD_B0, blue); + break; + + case 1: + sumobit.i2cWrite(REG_ADD_R1, red); + sumobit.i2cWrite(REG_ADD_G1, green); + sumobit.i2cWrite(REG_ADD_B1, blue); + break; + + } + } + + + + /** + * Return the RGB value of a known color. + */ + //% group="RGB LED" + //% weight=25 + //% blockGap=8 + //% blockId="sumobit_colors" + //% block="%color" + //% blockHidden=true + export function colors(color: RgbColors): number { + return color; + } + + + /** + * Converts red, green, blue channels into a RGB color. + * @param red Value of the red channel (0 - 255). eg: 255 + * @param green Value of the green channel (0 - 255). eg: 255 + * @param blue Value of the blue channel (0 - 255). eg: 255 + */ + //% group="RGB LED" + //% weight=24 + //% blockGap=30 + //% blockId="sumobit_rgb_value" + //% block="red %red green %green blue %blue" + //% red.min=0 red.max=255 + //% green.min=0 green.max=255 + //% blue.min=0 blue.max=255 + export function rgb(red: number, green: number, blue: number): number { + // Limit the value. + red = sumobit.limit(red, 0, 255); + green = sumobit.limit(green, 0, 255); + blue = sumobit.limit(blue, 0, 255); + + return ((red & 0xFF) << 16) | ((green & 0xFF) << 8) | (blue & 0xFF); + } + +} \ No newline at end of file diff --git a/servo.ts b/servo.ts new file mode 100644 index 0000000..1328450 --- /dev/null +++ b/servo.ts @@ -0,0 +1,63 @@ +/******************************************************************************* + * Functions for SUMO:BIT servo control + * + * Company: Cytron Technologies Sdn Bhd + * Website: http://www.cytron.io + * Email: support@cytron.io + *******************************************************************************/ + +// Servo Channel. +enum ServoChannel { + S1 = REG_ADD_SRV1_POS, + S2 = REG_ADD_SRV2_POS, + + //% block="all" + All = 1000, +}; + +namespace sumobit{ + + /** + * Disable the servo. + * @param servo Servo channel. + */ + //% group="Servos" + //% weight=38 + //% blockGap=8 + //% blockId=sumobit_disable_servo + //% block="disable servo %servo" + export function disableServo(servo: ServoChannel): void { + if (servo == ServoChannel.All) { + sumobit.i2cWrite(ServoChannel.S1, 0); + sumobit.i2cWrite(ServoChannel.S2, 0); + } + else { + sumobit.i2cWrite(servo, 0); + } + } + + + /** + * Set the position for servo (0-180 degrees). + * @param servo Servo channel. + * @param position Servo positon. eg: 90 + */ + //% group="Servos" + //% weight=39 + //% blockGap=8 + //% blockId=sumobit_set_servo_position + //% block="set servo %servo position to %position degrees" + //% position.min=0 position.max=180 + export function setServoPosition(servo: ServoChannel, position: number): void { + position = sumobit.limit(position, 0, 180); + + // pulseWidth = position * 20 / 18 + 50 + if (servo == ServoChannel.All) { + sumobit.i2cWrite(ServoChannel.S1, position); + sumobit.i2cWrite(ServoChannel.S2, position); + } + else { + sumobit.i2cWrite(servo, position); + } + } +}