added support for muliple i2c channels and TCS34725 colour sensor
parent
5a7cf002f5
commit
843ac9d202
|
|
@ -418,8 +418,8 @@ arduinoGenerator.forBlock['arduino_map'] = function (block) {
|
||||||
const unsupportedBlocks = [
|
const unsupportedBlocks = [
|
||||||
'wifi_connect', 'wifi_get_ip',
|
'wifi_connect', 'wifi_get_ip',
|
||||||
'neopixel_init', 'neopixel_set_color', 'neopixel_show',
|
'neopixel_init', 'neopixel_set_color', 'neopixel_show',
|
||||||
'colour_rgb', 'tuple_create_3',
|
'colour_rgb', 'tuple_create_3', 'tuple_index',
|
||||||
'i2c_init', 'i2c_scan', 'i2c_writeto', 'i2c_readfrom',
|
'i2c_init', 'i2c_scan', 'i2c_writeto', 'i2c_readfrom', 'tcs34725_read_colours',
|
||||||
'hid_key_press', 'hid_key_down', 'hid_key_up', 'hid_keyboard_type',
|
'hid_key_press', 'hid_key_down', 'hid_key_up', 'hid_keyboard_type',
|
||||||
'hid_mouse_move', 'hid_mouse_click', 'hid_mouse_scroll',
|
'hid_mouse_move', 'hid_mouse_click', 'hid_mouse_scroll',
|
||||||
'hid_gamepad_button', 'hid_gamepad_axis',
|
'hid_gamepad_button', 'hid_gamepad_axis',
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,17 @@ export const i2cCategory = {
|
||||||
name: 'I2C',
|
name: 'I2C',
|
||||||
colour: '200',
|
colour: '200',
|
||||||
contents: [
|
contents: [
|
||||||
{ kind: 'block', type: 'i2c_init' },
|
{ kind: 'block', type: 'i2c_init', fields: { CH: '0' } },
|
||||||
{ kind: 'block', type: 'i2c_scan' },
|
{ kind: 'block', type: 'i2c_scan', fields: { CH: '0' } },
|
||||||
{ kind: 'block', type: 'i2c_writeto' },
|
{ kind: 'block', type: 'i2c_writeto', fields: { CH: '0' } },
|
||||||
{ kind: 'block', type: 'i2c_readfrom' },
|
{ kind: 'block', type: 'i2c_readfrom', fields: { CH: '0' } },
|
||||||
|
{
|
||||||
|
kind: 'block',
|
||||||
|
type: 'tcs34725_read_colours',
|
||||||
|
fields: {
|
||||||
|
CH: '0',
|
||||||
|
ADDR: 41,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,22 @@ export const neopixelCategory = {
|
||||||
C: { shadow: { type: 'math_number', fields: { NUM: 0 } } },
|
C: { shadow: { type: 'math_number', fields: { NUM: 0 } } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
kind: 'block',
|
||||||
|
type: 'tuple_index',
|
||||||
|
inputs: {
|
||||||
|
TUPLE: {
|
||||||
|
shadow: {
|
||||||
|
type: 'tuple_create_3',
|
||||||
|
inputs: {
|
||||||
|
A: { shadow: { type: 'math_number', fields: { NUM: 255 } } },
|
||||||
|
B: { shadow: { type: 'math_number', fields: { NUM: 128 } } },
|
||||||
|
C: { shadow: { type: 'math_number', fields: { NUM: 0 } } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
kind: 'block',
|
kind: 'block',
|
||||||
type: 'neopixel_set_color',
|
type: 'neopixel_set_color',
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,25 @@ export const sensorsCategory = {
|
||||||
ECHO: { shadow: { type: 'math_number', fields: { NUM: 3 } } },
|
ECHO: { shadow: { type: 'math_number', fields: { NUM: 3 } } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
kind: 'block',
|
||||||
|
type: 'tcs34725_read_colours',
|
||||||
|
fields: {
|
||||||
|
CH: '0',
|
||||||
|
ADDR: 41,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: 'block',
|
||||||
|
type: 'tuple_index',
|
||||||
|
inputs: {
|
||||||
|
TUPLE: {
|
||||||
|
shadow: {
|
||||||
|
type: 'tcs34725_read_colours',
|
||||||
|
fields: { CH: '0', ADDR: 41 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,29 @@ Blockly.Blocks['tuple_create_3'] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['tuple_index'] = {
|
||||||
|
init() {
|
||||||
|
this.appendValueInput('TUPLE')
|
||||||
|
.setCheck(null)
|
||||||
|
.appendField('item')
|
||||||
|
.appendField(
|
||||||
|
new Blockly.FieldDropdown([
|
||||||
|
['0', '0'],
|
||||||
|
['1', '1'],
|
||||||
|
['2', '2'],
|
||||||
|
]),
|
||||||
|
'I',
|
||||||
|
)
|
||||||
|
.appendField('of tuple');
|
||||||
|
this.setOutput(true, 'Number');
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setColour(10);
|
||||||
|
this.setTooltip(
|
||||||
|
'Read one element from a tuple by index. Use with the TCS34725 block or any (a, b, c) value.',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Blockly.Blocks['neopixel_set_color'] = {
|
Blockly.Blocks['neopixel_set_color'] = {
|
||||||
init() {
|
init() {
|
||||||
this.appendValueInput('INDEX')
|
this.appendValueInput('INDEX')
|
||||||
|
|
@ -304,11 +327,18 @@ Blockly.Blocks['neopixel_show'] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// ─── I2C ──────────────────────────────────────────────────
|
// ─── I2C ──────────────────────────────────────────────────
|
||||||
|
// Hardware I2C peripheral id (0 or 1). Generated code uses i2c0 / i2c1 variables.
|
||||||
|
const I2C_CHANNEL_OPTIONS = [
|
||||||
|
['ch 0', '0'],
|
||||||
|
['ch 1', '1'],
|
||||||
|
];
|
||||||
|
|
||||||
Blockly.Blocks['i2c_init'] = {
|
Blockly.Blocks['i2c_init'] = {
|
||||||
init() {
|
init() {
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField('init I2C SDA pin')
|
.appendField('init I2C')
|
||||||
|
.appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
|
||||||
|
.appendField('SDA pin')
|
||||||
.appendField(new Blockly.FieldNumber(8, 0, 48, 1), 'SDA')
|
.appendField(new Blockly.FieldNumber(8, 0, 48, 1), 'SDA')
|
||||||
.appendField('SCL pin')
|
.appendField('SCL pin')
|
||||||
.appendField(new Blockly.FieldNumber(9, 0, 48, 1), 'SCL')
|
.appendField(new Blockly.FieldNumber(9, 0, 48, 1), 'SCL')
|
||||||
|
|
@ -317,17 +347,19 @@ Blockly.Blocks['i2c_init'] = {
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setColour(200);
|
this.setColour(200);
|
||||||
this.setTooltip('Initialize I2C bus');
|
this.setTooltip('Initialize an I2C bus. ESP32/RP2040: channel 0 or 1 maps to I2C(0) or I2C(1).');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Blockly.Blocks['i2c_scan'] = {
|
Blockly.Blocks['i2c_scan'] = {
|
||||||
init() {
|
init() {
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField('I2C scan devices');
|
.appendField('I2C')
|
||||||
|
.appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
|
||||||
|
.appendField('scan devices');
|
||||||
this.setOutput(true, 'Array');
|
this.setOutput(true, 'Array');
|
||||||
this.setColour(200);
|
this.setColour(200);
|
||||||
this.setTooltip('Scan for I2C devices, returns list of addresses');
|
this.setTooltip('Scan for I2C devices on the selected bus, returns list of addresses');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -335,26 +367,45 @@ Blockly.Blocks['i2c_writeto'] = {
|
||||||
init() {
|
init() {
|
||||||
this.appendValueInput('DATA')
|
this.appendValueInput('DATA')
|
||||||
.setCheck(null)
|
.setCheck(null)
|
||||||
.appendField('I2C write to address')
|
.appendField('I2C')
|
||||||
|
.appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
|
||||||
|
.appendField('write to address')
|
||||||
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
||||||
.appendField('data');
|
.appendField('data');
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setColour(200);
|
this.setColour(200);
|
||||||
this.setTooltip('Write data bytes to an I2C device');
|
this.setTooltip('Write data bytes to an I2C device on the selected bus');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Blockly.Blocks['i2c_readfrom'] = {
|
Blockly.Blocks['i2c_readfrom'] = {
|
||||||
init() {
|
init() {
|
||||||
this.appendDummyInput()
|
this.appendDummyInput()
|
||||||
.appendField('I2C read from address')
|
.appendField('I2C')
|
||||||
|
.appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
|
||||||
|
.appendField('read from address')
|
||||||
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
.appendField(new Blockly.FieldNumber(0, 0, 127, 1), 'ADDR')
|
||||||
.appendField('bytes')
|
.appendField('bytes')
|
||||||
.appendField(new Blockly.FieldNumber(1, 1, 256, 1), 'NBYTES');
|
.appendField(new Blockly.FieldNumber(1, 1, 256, 1), 'NBYTES');
|
||||||
this.setOutput(true, null);
|
this.setOutput(true, null);
|
||||||
this.setColour(200);
|
this.setColour(200);
|
||||||
this.setTooltip('Read N bytes from an I2C device');
|
this.setTooltip('Read N bytes from an I2C device on the selected bus');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks['tcs34725_read_colours'] = {
|
||||||
|
init() {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.appendField('TCS34725 read RGB')
|
||||||
|
.appendField(new Blockly.FieldDropdown(I2C_CHANNEL_OPTIONS), 'CH')
|
||||||
|
.appendField('address')
|
||||||
|
.appendField(new Blockly.FieldNumber(41, 1, 127, 1), 'ADDR');
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(65);
|
||||||
|
this.setTooltip(
|
||||||
|
'Read raw RGB channel counts as (R, G, B), each 0–65535. If there is no init I2C block for this channel, the bus is set up on GPIO 21 (SDA) and 22 (SCL) at 400 kHz.',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,13 @@ pythonGenerator.forBlock['tuple_create_3'] = function (block) {
|
||||||
return [`(${a}, ${b}, ${c})`, Order.ATOMIC];
|
return [`(${a}, ${b}, ${c})`, Order.ATOMIC];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pythonGenerator.forBlock['tuple_index'] = function (block) {
|
||||||
|
const tupleCode =
|
||||||
|
pythonGenerator.valueToCode(block, 'TUPLE', Order.MEMBER) || '(0, 0, 0)';
|
||||||
|
const i = block.getFieldValue('I') ?? '0';
|
||||||
|
return [`${tupleCode}[${i}]`, Order.MEMBER];
|
||||||
|
};
|
||||||
|
|
||||||
pythonGenerator.forBlock['neopixel_set_color'] = function (block) {
|
pythonGenerator.forBlock['neopixel_set_color'] = function (block) {
|
||||||
const index = pythonGenerator.valueToCode(block, 'INDEX', Order.NONE) || '0';
|
const index = pythonGenerator.valueToCode(block, 'INDEX', Order.NONE) || '0';
|
||||||
const color = pythonGenerator.valueToCode(block, 'COLOR', Order.NONE) || '(0, 0, 0)';
|
const color = pythonGenerator.valueToCode(block, 'COLOR', Order.NONE) || '(0, 0, 0)';
|
||||||
|
|
@ -268,35 +275,145 @@ pythonGenerator.forBlock['neopixel_show'] = function () {
|
||||||
|
|
||||||
// ─── I2C ──────────────────────────────────────────────────
|
// ─── I2C ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function i2cChannel(block) {
|
||||||
|
return block.getFieldValue('CH') === '1' ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
function i2cBusName(ch) {
|
||||||
|
return ch === '1' ? 'i2c1' : 'i2c0';
|
||||||
|
}
|
||||||
|
|
||||||
|
function i2cHardwareId(ch) {
|
||||||
|
return ch === '1' ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** True if an enabled "init I2C" block exists for this hardware channel (0 or 1). */
|
||||||
|
function workspaceHasI2cInitForChannel(block, ch) {
|
||||||
|
const ws = block.workspace;
|
||||||
|
if (!ws) return false;
|
||||||
|
const target = String(ch);
|
||||||
|
for (const b of ws.getAllBlocks(false)) {
|
||||||
|
if (!b.isEnabled()) continue;
|
||||||
|
if (b.type === 'i2c_init' && String(b.getFieldValue('CH') ?? '0') === target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Emit I2C bus init into definitions (runs before user code) when no init block is present. */
|
||||||
|
function ensureAutoI2cBusDefinition(block, ch, sda, scl, freq) {
|
||||||
|
if (DEVICE() === 'microbit') return;
|
||||||
|
if (workspaceHasI2cInitForChannel(block, ch)) return;
|
||||||
|
pythonGenerator.definitions_['import_machine'] = 'from machine import Pin, PWM, ADC, I2C';
|
||||||
|
const name = i2cBusName(ch);
|
||||||
|
const hw = i2cHardwareId(ch);
|
||||||
|
pythonGenerator.definitions_[`i2c_init_bus_${ch}`] =
|
||||||
|
`${name} = I2C(${hw}, sda=Pin(${sda}), scl=Pin(${scl}), freq=${freq})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TCS34725_RGB_HELPER = `_tcs34725_inited = [False, False]
|
||||||
|
|
||||||
|
def _tcs34725_rgb(bus, ch_idx, addr):
|
||||||
|
import time
|
||||||
|
global _tcs34725_inited
|
||||||
|
ch_idx = int(ch_idx) & 1
|
||||||
|
addr = int(addr)
|
||||||
|
if not _tcs34725_inited[ch_idx]:
|
||||||
|
time.sleep_ms(10)
|
||||||
|
bus.writeto(addr, bytes([0x80, 0x01]))
|
||||||
|
time.sleep_ms(10)
|
||||||
|
bus.writeto(addr, bytes([0x80, 0x03]))
|
||||||
|
bus.writeto(addr, bytes([0x81, 0xFF]))
|
||||||
|
bus.writeto(addr, bytes([0x8F, 0x03]))
|
||||||
|
_tcs34725_inited[ch_idx] = True
|
||||||
|
time.sleep_ms(5)
|
||||||
|
bus.writeto(addr, bytes([0x94]))
|
||||||
|
d = bus.readfrom(addr, 8)
|
||||||
|
r = d[3] << 8 | d[2]
|
||||||
|
g = d[5] << 8 | d[4]
|
||||||
|
b = d[7] << 8 | d[6]
|
||||||
|
return (r, g, b)
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TCS34725_RGB_HELPER_MB = `_tcs34725_inited_mb = False
|
||||||
|
|
||||||
|
def _tcs34725_rgb_mb(addr):
|
||||||
|
import time
|
||||||
|
from microbit import i2c
|
||||||
|
global _tcs34725_inited_mb
|
||||||
|
addr = int(addr)
|
||||||
|
if not _tcs34725_inited_mb:
|
||||||
|
time.sleep_ms(10)
|
||||||
|
i2c.write(addr, bytes([0x80, 0x01]))
|
||||||
|
time.sleep_ms(10)
|
||||||
|
i2c.write(addr, bytes([0x80, 0x03]))
|
||||||
|
i2c.write(addr, bytes([0x81, 0xFF]))
|
||||||
|
i2c.write(addr, bytes([0x8F, 0x03]))
|
||||||
|
_tcs34725_inited_mb = True
|
||||||
|
time.sleep_ms(5)
|
||||||
|
i2c.write(addr, bytes([0x94]))
|
||||||
|
d = i2c.read(addr, 8)
|
||||||
|
r = d[3] << 8 | d[2]
|
||||||
|
g = d[5] << 8 | d[4]
|
||||||
|
b = d[7] << 8 | d[6]
|
||||||
|
return (r, g, b)
|
||||||
|
`;
|
||||||
|
|
||||||
pythonGenerator.forBlock['i2c_init'] = function (block) {
|
pythonGenerator.forBlock['i2c_init'] = function (block) {
|
||||||
if (DEVICE() === 'microbit') return ''; // micro:bit has built-in i2c
|
if (DEVICE() === 'microbit') return ''; // micro:bit has built-in i2c
|
||||||
|
const ch = i2cChannel(block);
|
||||||
const sda = block.getFieldValue('SDA');
|
const sda = block.getFieldValue('SDA');
|
||||||
const scl = block.getFieldValue('SCL');
|
const scl = block.getFieldValue('SCL');
|
||||||
const freq = block.getFieldValue('FREQ');
|
const freq = block.getFieldValue('FREQ');
|
||||||
pythonGenerator.definitions_['import_machine'] = 'from machine import Pin, PWM, ADC, I2C';
|
pythonGenerator.definitions_['import_machine'] = 'from machine import Pin, PWM, ADC, I2C';
|
||||||
return `i2c = I2C(0, sda=Pin(${sda}), scl=Pin(${scl}), freq=${freq})\n`;
|
const name = i2cBusName(ch);
|
||||||
|
const hw = i2cHardwareId(ch);
|
||||||
|
return `${name} = I2C(${hw}, sda=Pin(${sda}), scl=Pin(${scl}), freq=${freq})\n`;
|
||||||
};
|
};
|
||||||
|
|
||||||
pythonGenerator.forBlock['i2c_scan'] = function (block) {
|
pythonGenerator.forBlock['i2c_scan'] = function (block) {
|
||||||
if (DEVICE() === 'microbit') {
|
if (DEVICE() === 'microbit') {
|
||||||
return ['[]', Order.ATOMIC]; // stub
|
return ['[]', Order.ATOMIC]; // stub
|
||||||
}
|
}
|
||||||
|
const ch = i2cChannel(block);
|
||||||
pythonGenerator.definitions_['import_machine'] = 'from machine import Pin, PWM, ADC, I2C';
|
pythonGenerator.definitions_['import_machine'] = 'from machine import Pin, PWM, ADC, I2C';
|
||||||
return ['i2c.scan()', Order.FUNCTION_CALL];
|
const bus = i2cBusName(ch);
|
||||||
|
return [`${bus}.scan()`, Order.FUNCTION_CALL];
|
||||||
};
|
};
|
||||||
|
|
||||||
pythonGenerator.forBlock['i2c_writeto'] = function (block) {
|
pythonGenerator.forBlock['i2c_writeto'] = function (block) {
|
||||||
if (DEVICE() === 'microbit') return '';
|
if (DEVICE() === 'microbit') return '';
|
||||||
|
const ch = i2cChannel(block);
|
||||||
const addr = block.getFieldValue('ADDR');
|
const addr = block.getFieldValue('ADDR');
|
||||||
const data = pythonGenerator.valueToCode(block, 'DATA', Order.NONE) || 'b""';
|
const data = pythonGenerator.valueToCode(block, 'DATA', Order.NONE) || 'b""';
|
||||||
return `i2c.writeto(${addr}, ${data})\n`;
|
const bus = i2cBusName(ch);
|
||||||
|
return `${bus}.writeto(${addr}, ${data})\n`;
|
||||||
};
|
};
|
||||||
|
|
||||||
pythonGenerator.forBlock['i2c_readfrom'] = function (block) {
|
pythonGenerator.forBlock['i2c_readfrom'] = function (block) {
|
||||||
if (DEVICE() === 'microbit') return ['b""', Order.ATOMIC];
|
if (DEVICE() === 'microbit') return ['b""', Order.ATOMIC];
|
||||||
|
const ch = i2cChannel(block);
|
||||||
const addr = block.getFieldValue('ADDR');
|
const addr = block.getFieldValue('ADDR');
|
||||||
const nbytes = block.getFieldValue('NBYTES');
|
const nbytes = block.getFieldValue('NBYTES');
|
||||||
return [`i2c.readfrom(${addr}, ${nbytes})`, Order.FUNCTION_CALL];
|
const bus = i2cBusName(ch);
|
||||||
|
return [`${bus}.readfrom(${addr}, ${nbytes})`, Order.FUNCTION_CALL];
|
||||||
|
};
|
||||||
|
|
||||||
|
pythonGenerator.forBlock['tcs34725_read_colours'] = function (block) {
|
||||||
|
const addr = Number(block.getFieldValue('ADDR')) || 41;
|
||||||
|
if (DEVICE() === 'microbit') {
|
||||||
|
pythonGenerator.definitions_['import_time'] = 'import time';
|
||||||
|
pythonGenerator.definitions_['tcs34725_rgb_mb'] = TCS34725_RGB_HELPER_MB;
|
||||||
|
return [`_tcs34725_rgb_mb(${addr})`, Order.FUNCTION_CALL];
|
||||||
|
}
|
||||||
|
const ch = i2cChannel(block);
|
||||||
|
ensureAutoI2cBusDefinition(block, ch, 21, 22, 400000);
|
||||||
|
pythonGenerator.definitions_['import_time'] = 'import time';
|
||||||
|
pythonGenerator.definitions_['tcs34725_rgb'] = TCS34725_RGB_HELPER;
|
||||||
|
const bus = i2cBusName(ch);
|
||||||
|
const chIdx = ch === '1' ? 1 : 0;
|
||||||
|
return [`_tcs34725_rgb(${bus}, ${chIdx}, ${addr})`, Order.FUNCTION_CALL];
|
||||||
};
|
};
|
||||||
|
|
||||||
// ─── Print ────────────────────────────────────────────────
|
// ─── Print ────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,16 @@ export const ROBOT_TEMPLATE_LIST = [
|
||||||
blockType: 'i2c_init',
|
blockType: 'i2c_init',
|
||||||
applyAs: 'statement',
|
applyAs: 'statement',
|
||||||
fields: [
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'CH',
|
||||||
|
label: 'Channel',
|
||||||
|
type: 'dropdown',
|
||||||
|
options: [
|
||||||
|
['0', '0'],
|
||||||
|
['1', '1'],
|
||||||
|
],
|
||||||
|
default: '0',
|
||||||
|
},
|
||||||
{ key: 'SDA', label: 'SDA pin', type: 'number', min: 0, max: 48, default: 8 },
|
{ key: 'SDA', label: 'SDA pin', type: 'number', min: 0, max: 48, default: 8 },
|
||||||
{ key: 'SCL', label: 'SCL pin', type: 'number', min: 0, max: 48, default: 9 },
|
{ key: 'SCL', label: 'SCL pin', type: 'number', min: 0, max: 48, default: 9 },
|
||||||
{ key: 'FREQ', label: 'Frequency (Hz)', type: 'number', min: 1, max: 1_000_000, default: 400_000 },
|
{ key: 'FREQ', label: 'Frequency (Hz)', type: 'number', min: 1, max: 1_000_000, default: 400_000 },
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue