806 lines
26 KiB
JavaScript
806 lines
26 KiB
JavaScript
import * as Blockly from 'blockly';
|
||
|
||
// ─── Pin I/O ──────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['pin_set_mode'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('set pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
|
||
.appendField('as')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['OUTPUT', 'OUT'],
|
||
['INPUT', 'IN'],
|
||
['INPUT_PULLUP', 'PULL_UP'],
|
||
]), 'MODE');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(230);
|
||
this.setTooltip('Configure a GPIO pin mode');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['pin_digital_write'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('digital write pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
|
||
.appendField('to')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['HIGH', '1'],
|
||
['LOW', '0'],
|
||
]), 'VALUE');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(230);
|
||
this.setTooltip('Write HIGH or LOW to a digital pin');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['pin_digital_read'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('digital read pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN');
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(230);
|
||
this.setTooltip('Read digital value from a pin (0 or 1)');
|
||
},
|
||
};
|
||
|
||
// ─── PWM ──────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['pwm_init'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('init PWM on pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
|
||
.appendField('freq')
|
||
.appendField(new Blockly.FieldNumber(1000, 1, 40000000, 1), 'FREQ')
|
||
.appendField('Hz');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(160);
|
||
this.setTooltip('Initialize PWM on a pin with a frequency');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['pwm_set_duty'] = {
|
||
init() {
|
||
this.appendValueInput('DUTY')
|
||
.setCheck('Number')
|
||
.appendField('set PWM duty on pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
|
||
.appendField('to');
|
||
this.appendDummyInput()
|
||
.appendField('(0-1023)');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(160);
|
||
this.setTooltip('Set PWM duty cycle (0-1023)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['pwm_set_freq'] = {
|
||
init() {
|
||
this.appendValueInput('FREQ')
|
||
.setCheck('Number')
|
||
.appendField('set PWM freq on pin')
|
||
.appendField(new Blockly.FieldNumber(2, 0, 48, 1), 'PIN')
|
||
.appendField('to');
|
||
this.appendDummyInput()
|
||
.appendField('Hz');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(160);
|
||
this.setTooltip('Set PWM frequency in Hz');
|
||
},
|
||
};
|
||
|
||
// ─── ADC ──────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['adc_read'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('read ADC on pin')
|
||
.appendField(new Blockly.FieldNumber(1, 0, 20, 1), 'PIN');
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(30);
|
||
this.setTooltip('Read analog value from ADC pin (0-4095)');
|
||
},
|
||
};
|
||
|
||
// ─── Time ─────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['sleep_seconds'] = {
|
||
init() {
|
||
this.appendValueInput('SECONDS')
|
||
.setCheck('Number')
|
||
.appendField('sleep');
|
||
this.appendDummyInput()
|
||
.appendField('seconds');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(120);
|
||
this.setTooltip('Pause execution for N seconds');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['sleep_ms'] = {
|
||
init() {
|
||
this.appendValueInput('MS')
|
||
.setCheck('Number')
|
||
.appendField('sleep');
|
||
this.appendDummyInput()
|
||
.appendField('milliseconds');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(120);
|
||
this.setTooltip('Pause execution for N milliseconds');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['ticks_ms'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('ticks (ms)');
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(120);
|
||
this.setTooltip('Get millisecond tick counter');
|
||
},
|
||
};
|
||
|
||
// ─── Random ───────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['random_int'] = {
|
||
init() {
|
||
this.appendValueInput('FROM')
|
||
.setCheck('Number')
|
||
.appendField('random integer from');
|
||
this.appendValueInput('TO')
|
||
.setCheck('Number')
|
||
.appendField('to');
|
||
this.setOutput(true, 'Number');
|
||
this.setInputsInline(true);
|
||
this.setColour(200);
|
||
this.setTooltip('Random integer N where from ≤ N ≤ to (inclusive)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['random_float'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('random float (0.0 to 1.0)');
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(200);
|
||
this.setTooltip('Random float in range [0.0, 1.0)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['random_uniform'] = {
|
||
init() {
|
||
this.appendValueInput('LOW')
|
||
.setCheck('Number')
|
||
.appendField('random float from');
|
||
this.appendValueInput('HIGH')
|
||
.setCheck('Number')
|
||
.appendField('to');
|
||
this.setOutput(true, 'Number');
|
||
this.setInputsInline(true);
|
||
this.setColour(200);
|
||
this.setTooltip('Random float in range [low, high]');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['random_seed'] = {
|
||
init() {
|
||
this.appendValueInput('SEED')
|
||
.setCheck('Number')
|
||
.appendField('random seed');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(200);
|
||
this.setTooltip('Set random seed for reproducible sequences (optional)');
|
||
},
|
||
};
|
||
|
||
// ─── WiFi ─────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['wifi_connect'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('connect WiFi SSID')
|
||
.appendField(new Blockly.FieldTextInput('MyNetwork'), 'SSID')
|
||
.appendField('password')
|
||
.appendField(new Blockly.FieldTextInput('password'), 'PASSWORD');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(290);
|
||
this.setTooltip('Connect to a WiFi network');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['wifi_get_ip'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('WiFi IP address');
|
||
this.setOutput(true, 'String');
|
||
this.setColour(290);
|
||
this.setTooltip('Get the current IP address');
|
||
},
|
||
};
|
||
|
||
// ─── NeoPixel ─────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['neopixel_init'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('init NeoPixel on pin')
|
||
.appendField(new Blockly.FieldNumber(48, 0, 48, 1), 'PIN')
|
||
.appendField('with')
|
||
.appendField(new Blockly.FieldNumber(1, 1, 1024, 1), 'NUM')
|
||
.appendField('LEDs');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(10);
|
||
this.setTooltip('Initialize a NeoPixel strip');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['colour_rgb'] = {
|
||
init() {
|
||
this.appendValueInput('R').setCheck('Number').appendField('colour R');
|
||
this.appendValueInput('G').setCheck('Number').appendField('G');
|
||
this.appendValueInput('B').setCheck('Number').appendField('B');
|
||
this.setOutput(true, 'Colour');
|
||
this.setInputsInline(true);
|
||
this.setColour(10);
|
||
this.setTooltip('RGB colour as array [R, G, B] (values 0–255)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['tuple_create_3'] = {
|
||
init() {
|
||
this.appendValueInput('A').appendField('tuple');
|
||
this.appendValueInput('B').appendField(',');
|
||
this.appendValueInput('C').appendField(',');
|
||
this.setOutput(true, 'Colour');
|
||
this.setInputsInline(true);
|
||
this.setColour(10);
|
||
this.setTooltip('Create a 3-element tuple (e.g. for NeoPixel colour). Use numbers or variables.');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['neopixel_set_color'] = {
|
||
init() {
|
||
this.appendValueInput('INDEX')
|
||
.setCheck('Number')
|
||
.appendField('set NeoPixel #');
|
||
this.appendValueInput('COLOR')
|
||
.setCheck(null)
|
||
.appendField('colour');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(10);
|
||
this.setTooltip('Set NeoPixel to a colour. Use the colour/tuple block or a variable (e.g. from a function parameter).');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['neopixel_show'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('NeoPixel show');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(10);
|
||
this.setTooltip('Push color data to NeoPixel strip');
|
||
},
|
||
};
|
||
|
||
// ─── I2C ──────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['i2c_init'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('init I2C SDA pin')
|
||
.appendField(new Blockly.FieldNumber(8, 0, 48, 1), 'SDA')
|
||
.appendField('SCL pin')
|
||
.appendField(new Blockly.FieldNumber(9, 0, 48, 1), 'SCL')
|
||
.appendField('freq')
|
||
.appendField(new Blockly.FieldNumber(400000, 1, 1000000, 1), 'FREQ');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(200);
|
||
this.setTooltip('Initialize I2C bus');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['i2c_scan'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('I2C scan devices');
|
||
this.setOutput(true, 'Array');
|
||
this.setColour(200);
|
||
this.setTooltip('Scan for I2C devices, returns list of addresses');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['i2c_writeto'] = {
|
||
init() {
|
||
this.appendValueInput('DATA')
|
||
.setCheck(null)
|
||
.appendField('I2C write to address')
|
||
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
||
.appendField('data');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(200);
|
||
this.setTooltip('Write data bytes to an I2C device');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['i2c_readfrom'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('I2C read from address')
|
||
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
||
.appendField('bytes')
|
||
.appendField(new Blockly.FieldNumber(1, 1, 256, 1), 'NBYTES');
|
||
this.setOutput(true, null);
|
||
this.setColour(200);
|
||
this.setTooltip('Read N bytes from an I2C device');
|
||
},
|
||
};
|
||
|
||
// ─── HID (Keyboard / Mouse / Gamepad) ─────────────────────
|
||
// USB HID key codes (Usage Page 0x07). Value is decimal for generator.
|
||
const HID_KEY_OPTIONS = [
|
||
['A', '4'], ['B', '5'], ['C', '6'], ['D', '7'], ['E', '8'], ['F', '9'], ['G', '10'],
|
||
['H', '11'], ['I', '12'], ['J', '13'], ['K', '14'], ['L', '15'], ['M', '16'], ['N', '17'],
|
||
['O', '18'], ['P', '19'], ['Q', '20'], ['R', '21'], ['S', '22'], ['T', '23'], ['U', '24'],
|
||
['V', '25'], ['W', '26'], ['X', '27'], ['Y', '28'], ['Z', '29'],
|
||
['1', '30'], ['2', '31'], ['3', '32'], ['4', '33'], ['5', '34'],
|
||
['6', '35'], ['7', '36'], ['8', '37'], ['9', '38'], ['0', '39'],
|
||
['Enter', '40'], ['Esc', '41'], ['Backspace', '42'], ['Tab', '43'], ['Space', '44'],
|
||
['-', '45'], ['=', '46'], ['[', '47'], [']', '48'], ['\\', '49'], [';', '51'],
|
||
["'", '52'], ['`', '53'], [',', '54'], ['.', '55'], ['/', '56'],
|
||
['F1', '58'], ['F2', '59'], ['F3', '60'], ['F4', '61'], ['F5', '62'],
|
||
['F6', '63'], ['F7', '64'], ['F8', '65'], ['F9', '66'], ['F10', '67'], ['F11', '68'], ['F12', '69'],
|
||
];
|
||
|
||
Blockly.Blocks['hid_key_press'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('HID key press')
|
||
.appendField(new Blockly.FieldDropdown(HID_KEY_OPTIONS), 'KEY');
|
||
this.appendDummyInput()
|
||
.appendField('modifier')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['none', '0'], ['Ctrl', '1'], ['Shift', '2'], ['Alt', '4'], ['GUI/Win', '8'],
|
||
['Ctrl+Shift', '3'], ['Ctrl+Alt', '5'], ['Shift+Alt', '6'],
|
||
]), 'MOD');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Press and release a key (keyboard HID)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_key_down'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('HID key down')
|
||
.appendField(new Blockly.FieldDropdown(HID_KEY_OPTIONS), 'KEY');
|
||
this.appendDummyInput()
|
||
.appendField('modifier')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['none', '0'], ['Ctrl', '1'], ['Shift', '2'], ['Alt', '4'], ['GUI/Win', '8'],
|
||
]), 'MOD');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Hold key down (keyboard HID)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_key_up'] = {
|
||
init() {
|
||
this.appendDummyInput().appendField('HID key up (release all)');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Release all keyboard keys');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_keyboard_type'] = {
|
||
init() {
|
||
this.appendValueInput('TEXT')
|
||
.setCheck('String')
|
||
.appendField('HID type text');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Type a string as keyboard input (HID)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_mouse_move'] = {
|
||
init() {
|
||
this.appendValueInput('X').setCheck('Number').appendField('HID mouse move X');
|
||
this.appendValueInput('Y').setCheck('Number').appendField('Y');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Move mouse relative (pixels)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_mouse_click'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('HID mouse click')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['left', '1'], ['right', '2'], ['middle', '4'],
|
||
]), 'BUTTON');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Click mouse button (press and release)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_mouse_scroll'] = {
|
||
init() {
|
||
this.appendValueInput('DELTA')
|
||
.setCheck('Number')
|
||
.appendField('HID mouse scroll');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Scroll wheel (positive = up, negative = down)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_gamepad_button'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('HID gamepad button')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['1', '0'], ['2', '1'], ['3', '2'], ['4', '3'], ['5', '4'], ['6', '5'],
|
||
['7', '6'], ['8', '7'], ['9', '8'], ['10', '9'], ['11', '10'], ['12', '11'],
|
||
['13', '12'], ['14', '13'], ['15', '14'], ['16', '15'],
|
||
]), 'BTN');
|
||
this.appendDummyInput()
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['press', '1'],
|
||
['release', '0'],
|
||
]), 'STATE');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Set gamepad button state (1-16)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['hid_gamepad_axis'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('HID gamepad axis')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['left X', '0'], ['left Y', '1'], ['right X', '2'], ['right Y', '3'],
|
||
['left trigger', '4'], ['right trigger', '5'],
|
||
]), 'AXIS');
|
||
this.appendValueInput('VALUE')
|
||
.setCheck('Number')
|
||
.appendField('value');
|
||
this.appendDummyInput().appendField('(-127 to 127)');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(330);
|
||
this.setTooltip('Set gamepad axis (-127 to 127, 0 = center)');
|
||
},
|
||
};
|
||
|
||
// ─── Print ────────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['print_text'] = {
|
||
init() {
|
||
this.appendValueInput('TEXT')
|
||
.setCheck(null)
|
||
.appendField('print');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(60);
|
||
this.setTooltip('Print to serial output');
|
||
},
|
||
};
|
||
|
||
// ─── Sound ───────────────────────────────────────────────
|
||
|
||
Blockly.Blocks['sound_play_tone_speaker'] = {
|
||
init() {
|
||
this.appendDummyInput().appendField('play tone on speaker');
|
||
this.appendValueInput('FREQ')
|
||
.setCheck('Number')
|
||
.appendField('freq');
|
||
this.appendDummyInput().appendField('Hz');
|
||
this.appendValueInput('DURATION')
|
||
.setCheck('Number')
|
||
.appendField('for');
|
||
this.appendDummyInput()
|
||
.appendField('ms')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['wait', 'TRUE'],
|
||
['continue', 'FALSE'],
|
||
]), 'WAIT');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Play a tone on the built-in speaker (micro:bit v2). "continue" runs code while tone plays.');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['sound_stop_speaker'] = {
|
||
init() {
|
||
this.appendDummyInput().appendField('stop speaker');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Stop sound on the built-in speaker (micro:bit v2)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['sound_play_tone'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('play tone on pin')
|
||
.appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
|
||
this.appendValueInput('FREQ')
|
||
.setCheck('Number')
|
||
.appendField('freq');
|
||
this.appendDummyInput().appendField('Hz');
|
||
this.appendValueInput('DURATION')
|
||
.setCheck('Number')
|
||
.appendField('for');
|
||
this.appendDummyInput()
|
||
.appendField('ms')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['wait', 'TRUE'],
|
||
['continue', 'FALSE'],
|
||
]), 'WAIT');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Play a tone via PWM on a specific pin. "continue" runs code while tone plays.');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['sound_stop'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('stop sound on pin')
|
||
.appendField(new Blockly.FieldNumber(0, 0, 48, 1), 'PIN');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Stop sound on a specific pin');
|
||
},
|
||
};
|
||
|
||
// ─── micro:bit Display ────────────────────────────────────
|
||
|
||
// Helper to add one row of 5 checkboxes (Pxy = pixel at row x, col y)
|
||
function addMicrobitDisplayRow(block, row) {
|
||
const input = block.appendDummyInput(`ROW${row}`);
|
||
for (let col = 0; col < 5; col++) {
|
||
const name = `P${row}${col}`;
|
||
input.appendField(new Blockly.FieldCheckbox(false), name);
|
||
}
|
||
}
|
||
|
||
Blockly.Blocks['microbit_display_all'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('micro:bit display 5×5');
|
||
for (let row = 0; row < 5; row++) {
|
||
addMicrobitDisplayRow(this, row);
|
||
}
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(10);
|
||
this.setTooltip('Click LEDs to set the 5×5 display (micro:bit only). On = 9, off = 0.');
|
||
},
|
||
};
|
||
|
||
// ─── SuperBit (Yahboom SuperBit V2, micro:bit only) ───────
|
||
|
||
Blockly.Blocks['superbit_motor_run'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('SuperBit motor')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['M1', 'M1'],
|
||
['M2', 'M2'],
|
||
['M3', 'M3'],
|
||
['M4', 'M4'],
|
||
]), 'MOTOR');
|
||
this.appendValueInput('SPEED')
|
||
.setCheck('Number')
|
||
.appendField('speed (-255 to 255)');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(45);
|
||
this.setTooltip('Run a SuperBit V2 motor (PCA9685 over I2C). Negative = reverse.');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['superbit_motor_stop_all'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('SuperBit motor stop all');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(45);
|
||
this.setTooltip('Stop all four SuperBit V2 motors.');
|
||
},
|
||
};
|
||
|
||
// ─── Sensors (HC-SR04 style sonar, all devices) ───────────
|
||
|
||
Blockly.Blocks['sonar_distance'] = {
|
||
init() {
|
||
this.appendValueInput('TRIG')
|
||
.setCheck('Number')
|
||
.appendField('sonar distance trigger');
|
||
this.appendValueInput('ECHO')
|
||
.setCheck('Number')
|
||
.appendField('echo');
|
||
this.setInputsInline(true);
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(65);
|
||
this.setTooltip('HC-SR04 style ultrasonic distance in cm. Trigger and echo pin numbers.');
|
||
},
|
||
};
|
||
|
||
// ─── Arduino-specific blocks ──────────────────────────────
|
||
|
||
Blockly.Blocks['arduino_builtin_led'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('set built-in LED')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['ON', '1'],
|
||
['OFF', '0'],
|
||
]), 'STATE');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(230);
|
||
this.setTooltip('Turn the built-in LED (pin 13) on or off');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_analog_write'] = {
|
||
init() {
|
||
this.appendValueInput('VALUE')
|
||
.setCheck('Number')
|
||
.appendField('analog write pin')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['3', '3'], ['5', '5'], ['6', '6'],
|
||
['9', '9'], ['10', '10'], ['11', '11'],
|
||
]), 'PIN')
|
||
.appendField('value');
|
||
this.appendDummyInput().appendField('(0-255)');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(160);
|
||
this.setTooltip('Write a PWM value (0-255) to a PWM-capable pin');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_analog_read'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('analog read')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['A0', '0'], ['A1', '1'], ['A2', '2'],
|
||
['A3', '3'], ['A4', '4'], ['A5', '5'],
|
||
]), 'CHANNEL');
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(30);
|
||
this.setTooltip('Read analog value from an ADC channel (0-1023)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_servo_attach'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('attach servo on pin')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['9', '9'], ['10', '10'], ['11', '11'],
|
||
['3', '3'], ['5', '5'], ['6', '6'],
|
||
]), 'PIN');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(260);
|
||
this.setTooltip('Attach a servo motor to a PWM pin');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_servo_write'] = {
|
||
init() {
|
||
this.appendValueInput('ANGLE')
|
||
.setCheck('Number')
|
||
.appendField('set servo on pin')
|
||
.appendField(new Blockly.FieldDropdown([
|
||
['9', '9'], ['10', '10'], ['11', '11'],
|
||
['3', '3'], ['5', '5'], ['6', '6'],
|
||
]), 'PIN')
|
||
.appendField('to');
|
||
this.appendDummyInput().appendField('degrees');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(260);
|
||
this.setTooltip('Set servo angle (0-180 degrees)');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_tone'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('play tone on pin')
|
||
.appendField(new Blockly.FieldNumber(8, 0, 13, 1), 'PIN');
|
||
this.appendValueInput('FREQ')
|
||
.setCheck('Number')
|
||
.appendField('freq');
|
||
this.appendDummyInput().appendField('Hz');
|
||
this.appendValueInput('DURATION')
|
||
.setCheck('Number')
|
||
.appendField('for');
|
||
this.appendDummyInput().appendField('ms');
|
||
this.setInputsInline(true);
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Play a tone on a digital pin using PWM');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_no_tone'] = {
|
||
init() {
|
||
this.appendDummyInput()
|
||
.appendField('stop tone on pin')
|
||
.appendField(new Blockly.FieldNumber(8, 0, 13, 1), 'PIN');
|
||
this.setPreviousStatement(true, null);
|
||
this.setNextStatement(true, null);
|
||
this.setColour(300);
|
||
this.setTooltip('Stop any tone playing on a digital pin');
|
||
},
|
||
};
|
||
|
||
Blockly.Blocks['arduino_map'] = {
|
||
init() {
|
||
this.appendValueInput('VALUE').setCheck('Number').appendField('map');
|
||
this.appendValueInput('FROM_LOW').setCheck('Number').appendField('from');
|
||
this.appendValueInput('FROM_HIGH').setCheck('Number').appendField('-');
|
||
this.appendValueInput('TO_LOW').setCheck('Number').appendField('to');
|
||
this.appendValueInput('TO_HIGH').setCheck('Number').appendField('-');
|
||
this.setInputsInline(true);
|
||
this.setOutput(true, 'Number');
|
||
this.setColour(200);
|
||
this.setTooltip('Re-map a number from one range to another');
|
||
},
|
||
};
|