Commit bd79dc6f authored by carlosperate's avatar carlosperate

Complete SPI blocks.

parent d9fd9c29
......@@ -187,7 +187,8 @@
<block type="text"></block>
</value>
</block>
<block type="spi_config"></block>
<block type="spi_setup"></block>
<block type="spi_transfer"></block>
<block type="spi_transfer_return"></block>
</category>
</xml>
......@@ -13,9 +13,9 @@ goog.provide('Blockly.Blocks.Arduino.spi');
goog.require('Blockly.Arduino');
Blockly.Blocks.Arduino.spi.HUE = 255;
Blockly.Blocks.Arduino.spi.HUE = 180;
Blockly.Blocks['spi_config'] = {
Blockly.Blocks['spi_setup'] = {
/**
* Block for the spi configuration. Info in the setHelpUrl link.
* @this Blockly.Block
......@@ -24,32 +24,48 @@ Blockly.Blocks['spi_config'] = {
this.setHelpUrl('http://arduino.cc/en/Reference/SPI');
this.setColour(Blockly.Blocks.Arduino.spi.HUE);
this.appendDummyInput()
.appendField('SPI Configuration:');
.appendField('Setup')
.appendField(new Blockly.FieldDropdown(
Blockly.Arduino.Boards.selected.spi), 'SPI_ID')
.appendField('configuration:');
this.appendDummyInput()
.appendField('Data Shift')
.appendField('data shift')
.appendField(
new Blockly.FieldDropdown(
[['MSBFIRST', 'MSBFIRST'],['LSBFIRST', 'LSBFIRST']]),
[['MSBFIRST', 'MSBFIRST'], ['LSBFIRST', 'LSBFIRST']]),
'SPI_SHIFT_ORDER');
this.appendDummyInput()
.appendField('Clock Divide')
.appendField('clock divide')
.appendField(
new Blockly.FieldDropdown(
Blockly.Arduino.Boards.selected.spiClockDivide),
'SPI_CLOCK_DIVIDE');
this.appendDummyInput()
.appendField('SPI Mode (Idle - Edge)')
.appendField('SPI mode (idle - edge)')
.appendField(
new Blockly.FieldDropdown(
[['0 (Low - Falling)', 'SPI_MODE0'],
[['0 (Low - Falling)', 'SPI_MODE0'],
['1 (Low - Rising)', 'SPI_MODE1'],
['2 (High - Falling)', 'SPI_MODE2'],
['3 (High - Rising)', 'SPI_MODE3']]),
'SPI_MODE');
this.setTooltip('Configures the SPI peripheral');
this.setTooltip('Configures the SPI peripheral.');
},
/** Updates the content of the the board SPI related fields. */
/**
* Returns the selected SPI instance.
* @return {!string} SPI instance name.
* @this Blockly.Block
*/
getSpiSetupInstance: function() {
return this.getFieldValue('SPI_ID');
},
/**
* Updates the content of the the board SPI related fields.
* @this Blockly.Block
*/
updateFields: function() {
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'SPI_ID', 'spi');
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'SPI_CLOCK_DIVIDE', 'spiClockDivide');
}
......@@ -61,7 +77,7 @@ Blockly.Blocks['spi_transfer'] = {
* @this Blockly.Block
*/
init: function() {
// Drop down list to contains all digital pins plus an option for 'none'
// Drop down list to contain all digital pins plus an option for 'none'
var slaveNone = [['none', 'none']];
var digitalPinsExtended = slaveNone.concat(
Blockly.Arduino.Boards.selected.digitalPins);
......@@ -69,31 +85,120 @@ Blockly.Blocks['spi_transfer'] = {
this.setHelpUrl('http://arduino.cc/en/Reference/SPITransfer');
this.setColour(Blockly.Blocks.Arduino.spi.HUE);
this.appendDummyInput()
.appendField('To SPI Slave pin')
.appendField(new Blockly.FieldDropdown(
Blockly.Arduino.Boards.selected.spi), 'SPI_ID');
this.appendValueInput('SPI_DATA', '')
.appendField('transfer');
this.appendDummyInput('')
.appendField('to slave pin')
.appendField(
new Blockly.FieldDropdown(digitalPinsExtended), 'SPI_SS');
this.appendDummyInput('')
.appendField('transfer');
this.appendValueInput('SPI_DATA', '');
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip('Send SPI message to an specified slave device');
this.setTooltip('Send a SPI message to an specified slave device.');
},
/**
* Called whenever anything on the workspace changes.
* It checks the instances of stepper_config and attaches a warning to this
* block if not valid data is found.
* @this Blockly.Block
*/
onchange: function() {
if (!this.workspace) { return; } // Block has been deleted.
// Get the Serial instance from this block
var thisInstanceName = this.getFieldValue('SPI_ID');
// Iterate through blocks to find a setup instance for the same SPI id.
var blocks = Blockly.mainWorkspace.getAllBlocks();
var setupInstancePresent = false;
for (var x = 0, length_ = blocks.length; x < length_; x++) {
var func = blocks[x].getSpiSetupInstance;
if (func) {
var setupBlockInstanceName = func.call(blocks[x]);
if (thisInstanceName == setupBlockInstanceName) {
setupInstancePresent = true;
}
}
}
if (!setupInstancePresent) {
this.setWarningText(
'A setup block for ' + thisInstanceName + ' must be added to the ' +
'workspace to use this block!', 'spi_setup');
} else {
this.setWarningText(null, 'spi_setup');
}
},
/**
* Retrieves the type of the selected variable, Arduino code returns a byte,
* for now set it to integer..
* for now set it to integer.
* @return {!string} Blockly type.
* @this Blockly.Block
*/
getType: function() {
return Blockly.StaticTyping.blocklyType.INTEGER;
},
/** Updates the content of the board SPI related fields. */
/**
* Updates the content of the board SPI related fields.
* @this Blockly.Block
*/
updateFields: function() {
//TODO: Probably need to implement this function code here, as the block
// needs the digital IO extended. Or a new element on the boards
// profile could be created for the SPI slave pin.
Blockly.Arduino.Boards.refreshBlockFieldDropdown(
this, 'SPI_SS', 'digitalPins');
// Special case, otherwise Blockly.Arduino.Boards.refreshBlockFieldDropdown
var field = this.getField('SPI_SS');
var fieldValue = field.getValue();
var slaveNone = [['none', 'none']];
field.menuGenerator_ =
slaveNone.concat(Blockly.Arduino.Boards.selected['digitalPins']);
var currentValuePresent = false;
for (var i = 0, length_ = field.menuGenerator_.length; i < length_; i++) {
if (fieldValue == field.menuGenerator_[i][1]) {
currentValuePresent = true;
}
}
// If the old value is not present any more, add a warning to the block.
if (!currentValuePresent) {
this.setWarningText(
'Old pin value ' + fieldValue + ' is no longer available.', 'bPin');
} else {
this.setWarningText(null, 'bPin');
}
}
};
Blockly.Blocks['spi_transfer_return'] = {
/**
* Block for for the spi transfer with a return value.
* @this Blockly.Block
*/
init: function() {
// Drop down list to contain all digital pins plus an option for 'none'
var slaveNone = [['none', 'none']];
var digitalPinsExtended = slaveNone.concat(
Blockly.Arduino.Boards.selected.digitalPins);
this.setHelpUrl('http://arduino.cc/en/Reference/SPITransfer');
this.setColour(Blockly.Blocks.Arduino.spi.HUE);
this.appendDummyInput()
.appendField(new Blockly.FieldDropdown(
Blockly.Arduino.Boards.selected.spi), 'SPI_ID');
this.appendValueInput('SPI_DATA', '')
.appendField('transfer');
this.appendDummyInput('')
.appendField('to slave pin')
.appendField(
new Blockly.FieldDropdown(digitalPinsExtended), 'SPI_SS');
this.setInputsInline(true);
this.setOutput(true);
this.setTooltip('Send a SPI message to an specified slave device and get ' +
'data back.');
},
/** Same as spi_transfer block */
onchange: Blockly.Blocks['spi_transfer'].onchange,
/** Same as spi_transfer block */
getType: Blockly.Blocks['spi_transfer'].getType,
/** Same as spi_transfer block */
updateFields: Blockly.Blocks['spi_transfer'].updateFields
};
......@@ -58,6 +58,8 @@ Blockly.Arduino.ORDER_CONDITIONAL = 13; // expr ? expr : expr
Blockly.Arduino.ORDER_ASSIGNMENT = 14; // = *= /= ~/= %= += -= <<= >>= &= ^= |=
Blockly.Arduino.ORDER_NONE = 99; // (...)
/**
* Arduino generator short name for
* Blockly.Generator.prototype.FUNCTION_NAME_PLACEHOLDER_
......@@ -158,7 +160,7 @@ Blockly.Arduino.finish = function(code) {
}
var allDefs = includes.join('\n') + '\n' + imports.join('\n') + '\n' +
definitions.join('\n') + '\n' + functions.join('\n\n') +
definitions.join('\n') + '\n\n' + functions.join('\n\n') +
'\n\nvoid setup() {\n ' + setups.join('\n ') + '\n}';
return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code;
};
......@@ -213,6 +215,26 @@ Blockly.Arduino.addFunction = function(preferedName, code) {
return Blockly.Arduino.functionNames_[preferedName];
};
/**
* Description.
* @param {!Blockly.Block}
*/
Blockly.Arduino.reservePin = function(block, pin, pinType, warningTag) {
if (Blockly.Arduino.pins_[pin] !== undefined) {
if (Blockly.Arduino.pins_[pin] != pinType) {
block.setWarningText(
'Pin ' + pin + ' is needed for ' + warningTag + ' as pin ' + pinType +
'. Already used as ' + Blockly.Arduino.pins_[pin] + ' instead.',
warningTag);
} else {
block.setWarningText(null, warningTag);
}
} else {
Blockly.Arduino.pins_[pin] = pinType;
block.setWarningText(null, warningTag);
}
};
/**
* Naked values are top-level blocks with outputs that aren't plugged into
* anything. A trailing semicolon is needed to make this legal.
......
......@@ -59,6 +59,7 @@ Blockly.Arduino.Boards.pinTypes = {
SPI: 'SPI'
};
/** Arduino Uno board profile. */
Blockly.Arduino.Boards.uno = {
name: 'Arduino Uno',
......@@ -75,7 +76,7 @@ Blockly.Arduino.Boards.uno = {
['14400', '14400'], ['19200', '19200'], ['28800', '28800'],
['31250', '31250'], ['38400', '38400'], ['57600', '57600'],
['115200', '115200']],
spi: [['spi', 'SPI']],
spi: [['SPI', 'SPI']],
spiPins: { spi: [['MOSI', '11'], ['MISO', '12'], ['SCK', '13']] },
spiClockDivide: [['2 (8MHz)', 'SPI_CLOCK_DIV2'],
['4 (4MHz)', 'SPI_CLOCK_DIV4'],
......@@ -84,8 +85,8 @@ Blockly.Arduino.Boards.uno = {
['32 (500KHz)', 'SPI_CLOCK_DIV32'],
['64 (250KHz)', 'SPI_CLOCK_DIV64'],
['128 (125KHz)', 'SPI_CLOCK_DIV128']],
i2c: [['i2c', 'Wire']],
i2cPins: { i2c: [['SDA', 'A4'], ['SCL', 'A5']] },
i2c: [['I2C', 'Wire']],
i2cPins: { I2C: [['SDA', 'A4'], ['SCL', 'A5']] },
i2cSpeed: [['100kHz', '100000L'], ['400kHz', '400000L']],
builtinLed: [['BUILTIN_1', '13']],
interrupt: [['interrupt0', '2'], ['interrupt1', '3']]
......@@ -128,8 +129,8 @@ Blockly.Arduino.Boards.mega = {
digitalPins: Blockly.Arduino.Boards.generateDigitalIo(0, 53),
pwmPins: Blockly.Arduino.Boards.generateDigitalIo(2, 13).concat(
Blockly.Arduino.Boards.generateDigitalIo(44, 46)),
serial: [['serial', 'Serial'], ['serial1', 'Serial1'],
['serial2', 'Serial2'], ['serial3', 'Serial3']],
serial: [['serial', 'Serial'], ['serial_1', 'Serial1'],
['serial_2', 'Serial2'], ['serial_3', 'Serial3']],
serialPins: {
serial: [['TX', '0'], ['RX', '1']],
serial1: [['TX', '18'], ['TX', '19']],
......@@ -137,12 +138,12 @@ Blockly.Arduino.Boards.mega = {
serial3: [['TX', '14'], ['TX', '15']]
},
serialSpeed: Blockly.Arduino.Boards.uno.serialSpeed,
spi: [['spi', 'SPI']],
spiPins: { spi: [['MOSI', '51'], ['MISO', '50'], ['SCK', '52']] },
spi: [['SPI', 'SPI']],
spiPins: { SPI: [['MOSI', '51'], ['MISO', '50'], ['SCK', '52']] },
//TODO: confirm the clock divides are the same for the DUE and UNO
spiClockDivide: Blockly.Arduino.Boards.uno.spiClockDivide,
i2c: [['i2c', 'Wire']],
i2cPins: { i2c: [['SDA', '20'], ['SCL', '21']] },
i2c: [['I2C', 'Wire']],
i2cPins: { I2C: [['SDA', '20'], ['SCL', '21']] },
i2cSpeed: [['100kHz', '100000L'], ['400kHz', '400000L']],
builtinLed: Blockly.Arduino.Boards.uno.builtinLed,
interrupt: [['interrupt0', '2'], ['interrupt1', '3'], ['interrupt2', '21'],
......@@ -161,12 +162,12 @@ Blockly.Arduino.Boards.leonardo = {
serial: Blockly.Arduino.Boards.uno.serial,
serialPins: Blockly.Arduino.Boards.uno.serialPins,
serialSpeed: Blockly.Arduino.Boards.uno.serialSpeed,
spi: Blockly.Arduino.Boards.uno.spi,
spiPins: { spi: [['MOSI', 'ICSP-4'], ['MISO', 'ICSP-1'], ['SCK', 'ICSP-3']] },
spi: [['SPI', 'SPI']],
spiPins: { SPI: [['MOSI', 'ICSP-4'], ['MISO', 'ICSP-1'], ['SCK', 'ICSP-3']] },
//TODO: confirm the clock divides are the same for the Leonardo and UNO
spiClockDivide: Blockly.Arduino.Boards.uno.spiClockDivide,
i2c: Blockly.Arduino.Boards.uno.i2c,
i2cPins: { i2c: [['SDA', '2'], ['SCL', '3']] },
i2c: [['I2C', 'Wire']],
i2cPins: { I2C: [['SDA', '2'], ['SCL', '3']] },
i2cSpeed: Blockly.Arduino.Boards.uno.i2cSpeed,
builtinLed: Blockly.Arduino.Boards.uno.builtinLed,
interrupt: [['interrupt0', '3'], ['interrupt1', '2'], ['interrupt2', '0'],
......@@ -224,6 +225,8 @@ Blockly.Arduino.Boards.refreshBlockFieldDropdown =
// If the old value is not present any more, add a warning to the block.
if (!currentValuePresent) {
block.setWarningText(
'The old pin value ' + fieldValue + ' is no longer available.');
'The old pin value ' + fieldValue + ' is no longer available.', 'bPin');
} else {
block.setWarningText(null, 'bPin');
}
};
......@@ -14,7 +14,7 @@ goog.require('Blockly.Arduino');
/**
* Code generator for the SPI configuration block. It does not add any LoC to
* Code generator for the SPI configuration block. It does not add any LoC to
* the loop(), but it generates code for the setup() function.
* Arduino code: #include <SPI.h>
* setup() { SPI.setBitOrder(X);
......@@ -24,28 +24,26 @@ goog.require('Blockly.Arduino');
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['spi_config'] = function(block) {
Blockly.Arduino['spi_setup'] = function(block) {
var spiShift = block.getFieldValue('SPI_SHIFT_ORDER');
var spiClockDivide = block.getFieldValue('SPI_CLOCK_DIVIDE');
var spiMode = block.getFieldValue('SPI_MODE');
Blockly.Arduino.definitions_['define_spi'] = '#include <SPI.h>';
Blockly.Arduino.setups_['setup_spi_order'] =
'SPI.setBitOrder(' + spiShift + ');';
Blockly.Arduino.setups_['setup_spi_mode'] =
'SPI.setDataMode(' + spiMode + ');';
Blockly.Arduino.setups_['setup_spi_div'] =
'SPI.setClockDivider(' + spiClockDivide + ');';
Blockly.Arduino.setups_['setup_spi_begin'] =
'SPI.begin();';
Blockly.Arduino.addInclude('spi', '#include <SPI.h>');
Blockly.Arduino.addSetup('setup_spi_order',
'SPI.setBitOrder(' + spiShift + ');', true);
Blockly.Arduino.addSetup('setup_spi_mode',
'SPI.setDataMode(' + spiMode + ');', true);
Blockly.Arduino.addSetup('spi_div',
'SPI.setClockDivider(' + spiClockDivide + ');', true);
Blockly.Arduino.addSetup('spi_begin', 'SPI.begin();', true);
var code = '';
return code;
return '';
};
/**
* Code generator for the SPI transfer block.
* SPI bus can have several slaves, which are selected using a digital output
* Code generator for the SPI transfer block.
* SPI bus can have several slaves, which are selected using a digital output
* as a SS pin. This digital pin will be configured as a normal output.
* Arduino code: #include <SPI.h>
* setup { pinMode(X, OUTPUT); }
......@@ -56,70 +54,67 @@ Blockly.Arduino['spi_config'] = function(block) {
* @return {string} Completed code.
*/
Blockly.Arduino['spi_transfer'] = function(block) {
var spiId = block.getFieldValue('SPI_ID');
var spiSs = block.getFieldValue('SPI_SS');
var spiData = Blockly.Arduino.valueToCode(
block, 'SPI_DATA', Blockly.Arduino.ORDER_ATOMIC) || '0';
var code = '';
Blockly.Arduino.definitions_['define_spi'] = '#include <SPI.h>';
Blockly.Arduino.setups_['setup_spi_begin'] = 'SPI.begin();';
Blockly.Arduino.addInclude('spi', '#include <SPI.h>');
Blockly.Arduino.addSetup('spi_begin', 'SPI.begin();', false);
// Configure SPI pins (MOSI, MISO, SCK) as used, or warn if already in use
var warningText = '';
var pinType = Blockly.Arduino.Boards.pinTypes.SPI;
// Reserve SPI pins MOSI, MISO, and SCK
for (var i = 0; i < Blockly.Arduino.Boards.selected.spiPins.length; i++) {
var pin_number = Blockly.Arduino.Boards.selected.spiPins[i][1];
if (pin_number in Blockly.Arduino.pins_) {
if (Blockly.Arduino.pins_[pin_number] != pinType) {
warningText = warningText +
'SPI needs pin ' + Blockly.Arduino.Boards.selected.spiPins[i][1] +
' as ' + Blockly.Arduino.Boards.selected.spiPins[i][0] + '\n' +
'Pin ' + pin_number + ' already used as ' +
Blockly.Arduino.pins_[pin_number] + '\n';
}
} else {
// First time this IO pin is used, so configure it
Blockly.Arduino.pins_[pin_number] = pinType;
}
}
if (warningText === '') {
block.setWarningText(null);
} else {
block.setWarningText(warningText);
Blockly.Arduino.reservePin(block,
Blockly.Arduino.Boards.selected.spiPins[i][1],
Blockly.Arduino.Boards.pinTypes.SPI,
'SPI ' + Blockly.Arduino.Boards.selected.spiPins[i][0]);
}
// Configure the Slave Select as a normal output if a pin is used
if (spiSs != 'none') {
pinType = Blockly.Arduino.Boards.pinTypes.OUTPUT;
var setUpKey = 'setup_io_' + spiSs;
Blockly.Arduino.setups_[setUpKey] = 'pinMode(' + spiSs + ', OUTPUT);';
// If the IO has been configured already set a warning for the user
if (spiSs in Blockly.Arduino.pins_) {
if (Blockly.Arduino.pins_[spiSs] != pinType) {
warningText = warningText + 'Pin already used as ' +
Blockly.Arduino.pins_[spiSs];
}
} else {
// First time this IO pin is used, so configure it
Blockly.Arduino.pins_[spiSs] = pinType;
}
}
if (warningText === '') {
block.setWarningText(null);
} else {
block.setWarningText(warningText);
}
if (spiSs !== 'none') {
Blockly.Arduino.reservePin(
block, spiSs, Blockly.Arduino.Boards.pinTypes.OUTPUT, 'SPI Slave pin');
var setupCode = 'pinMode(' + spiSs + ', OUTPUT);';
Blockly.Arduino.addSetup('io_' + spiSs, setupCode, false);
} // else means the SS pin is always set for the device
// Add the code, but only use a SS pin if one is selected
if (spiSs != 'none') {
code = code + 'digitalWrite(' + spiSs + ', HIGH);\n';
var code = [];
if (spiSs !== 'none') {
code.push('digitalWrite(' + spiSs + ', HIGH);');
}
code = code + 'SPI.transfer(' + spiData + ');\n';
if (spiSs != 'none') {
code = code + 'digitalWrite(' + spiSs + ', LOW);\n';
code.push('SPI.transfer(' + spiData + ');');
if (spiSs !== 'none') {
code.push('digitalWrite(' + spiSs + ', LOW);');
}
return code;
return code.join('\n') + '\n';
};
/**
* Code generator for the SPI transfer block with a return value.
* The rest is the same as the spi_transfer block.
* @param {!Blockly.Block} block Block to generate the code from.
* @return {string} Completed code.
*/
Blockly.Arduino['spi_transfer_return'] = function(block) {
var spiSs = block.getFieldValue('SPI_SS');
var spiCode = Blockly.Arduino['spi_transfer'](block);
var code;
if (spiSs === 'none') {
var spiData = Blockly.Arduino.valueToCode(
block, 'SPI_DATA', Blockly.Arduino.ORDER_ATOMIC) || '0';
code = 'SPI.transfer(' + spiData + ')';
} else {
var func = [
'int ' + Blockly.Arduino.DEF_FUNC_NAME + '() {',
' int spiReturn = 0;',
' ' + spiCode.replace('SPI.transfer', 'spiReturn = SPI.transfer')
.replace(/\n/g, '\n ') + 'return spiReturn;',
'}'];
var functionName = Blockly.Arduino.addFunction(
'spiReturnSlave' + spiSs, func.join('\n'));
code = functionName + '()';
}
return [code, Blockly.Arduino.ORDER_UNARY_POSTFIX];
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment