From fbf12941ad4edb9e073ada8a0e932a5317c61f0b Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 07:46:58 -0800 Subject: [PATCH 1/6] Refactor SD card blocks into separate module. --- src/modules/blockly/generators/propc/gpio.js | 440 ----------------- .../blockly/generators/propc/sd_card.js | 467 ++++++++++++++++++ src/modules/editor.js | 1 + 3 files changed, 468 insertions(+), 440 deletions(-) create mode 100644 src/modules/blockly/generators/propc/sd_card.js diff --git a/src/modules/blockly/generators/propc/gpio.js b/src/modules/blockly/generators/propc/gpio.js index 53495d18..269122fb 100644 --- a/src/modules/blockly/generators/propc/gpio.js +++ b/src/modules/blockly/generators/propc/gpio.js @@ -2249,446 +2249,6 @@ Blockly.propc.wav_stop = function() { return 'wav_stop();\n'; }; -// ---------------------------------------------------------------- -// ----------------- SD Card file blocks -------------------------- -// ---------------------------------------------------------------- - -/** - * SD Card Initialization - * @type {{ - * init: Blockly.Blocks.sd_init.init, - * helpUrl: string - * }} - */ -Blockly.Blocks.sd_init = { - helpUrl: Blockly.MSG_SD_HELPURL, - init: function() { - const profile = getDefaultProfile(); - this.setTooltip(Blockly.MSG_SD_INIT_TOOLTIP); - this.setColour(colorPalette.getColor('output')); - this.appendDummyInput() - .appendField('SD initialize DO') - .appendField(new Blockly.FieldDropdown( - profile.digital), 'DO') - .appendField('CLK') - .appendField(new Blockly.FieldDropdown( - profile.digital), 'CLK') - .appendField('DI') - .appendField(new Blockly.FieldDropdown( - profile.digital), 'DI') - .appendField('CS') - .appendField(new Blockly.FieldDropdown( - profile.digital), 'CS'), - this.setPreviousStatement(true, 'Block'); - this.setNextStatement(true, null); - }, -}; - -/** - * - * @return {string} - */ -Blockly.propc.sd_init = function() { - // Global variable for SD file processing - this.myType = 'fp'; - - if (!this.disabled) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + - this.getFieldValue('DO') + ', ' + - this.getFieldValue('CLK') + ', ' + - this.getFieldValue('DI') + ', ' + - this.getFieldValue('CS') + ');'; - - // Declare the global variable - Blockly.propc.global_vars_[ - this.myType + 'global'] = 'FILE *' + this.myType + ';'; - } - - return ''; -}; - -/** - * - * @type {{ - * init: Blockly.Blocks.sd_open.init, - * helpUrl: string, - * onchange: Blockly.Blocks.sd_open.onchange - * }} - */ -Blockly.Blocks.sd_open = { - helpUrl: Blockly.MSG_SD_HELPURL, - init: function() { - this.setTooltip(Blockly.MSG_SD_OPEN_TOOLTIP); - this.setColour(colorPalette.getColor('output')); - this.appendDummyInput('MODE') - .appendField('SD file open') - .appendField(new Blockly.FieldTextInput( - 'filename.txt', - function(filename) { - filename = filename.replace(/[^A-Z0-9a-z_.]/g, '').toLowerCase(); - const filenamePart = filename.split('.'); - if (filenamePart[0].length > 8) { - filenamePart[0].length = 8; - } - if (!filenamePart[1]) { - filenamePart[1] = 'TXT'; - } else if (filenamePart[1].length > 3) { - filenamePart[1].length = 3; - } - return filenamePart[0] + '.' + filenamePart[1]; - }), 'FILENAME') - .appendField(new Blockly.FieldDropdown([ - ['as read-only', 'r'], - ['as read-write', 'w'], - ]), 'MODE'); - this.setInputsInline(false); - this.setPreviousStatement(true, 'Block'); - this.setNextStatement(true, null); - }, - - /** - * Check for an active sd_init block in the project. The block must exist - * and not be disabled. - */ - onchange: function() { - const project = getProjectInitialState(); - if (project.boardType.name !== 'activity-board' && - project.boardType.name !== 'heb-wx') { - const block = Blockly.getMainWorkspace().getBlocksByType( - 'sd_init', false); - if (block.length === 0 || ! block[0].isEnabled()) { - this.setWarningText('WARNING: You must use a SD' + - ' initialize\nblock at the beginning of your program!'); - } else { - this.setWarningText(null); - } - } - }, -}; - -/** - * SD Card Open C code generator - * @return {string} - */ -Blockly.propc.sd_open = function() { - const filename = this.getFieldValue('FILENAME'); - const mode = this.getFieldValue('MODE'); - let initFound = false; - - const initSdBlock = Blockly.getMainWorkspace().getBlocksByType( - 'sd_init', false); - if (initSdBlock.length > 0 && initSdBlock[0].isEnabled()) { - initFound = true; - } else { - const project = getProjectInitialState(); - if (project.boardType.name !== 'activity-board' && - project.boardType.name !== 'heb-wx') { - return '/** WARNING: You must use a SD initialize block at the' + - ' beginning of your program! **/\r'; - } - } - - // Quietly mount the sd card filesystem - const profile = getDefaultProfile(); - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');\r'; - } - - return `fp = fopen("${filename}","${mode}");\r`; -}; - -/** - * - * @type {{ - * init: Blockly.Blocks.sd_read.init, - * mutationToDom: (function(): HTMLElement), - * helpUrl: string, - * setSdMode: Blockly.Blocks.sd_read.setSdMode, - * onchange: Blockly.Blocks.sd_read.onchange, - * domToMutation: Blockly.Blocks.sd_read.domToMutation - * }} - */ -Blockly.Blocks.sd_read = { - helpUrl: Blockly.MSG_SD_HELPURL, - init: function() { - this.setTooltip(Blockly.MSG_SD_READ_TOOLTIP); - this.setColour(colorPalette.getColor('output')); - this.setSdMode('fwrite'); - this.setInputsInline(true); - this.setPreviousStatement(true, 'Block'); - this.setNextStatement(true, null); - }, - mutationToDom: function() { - const container = document.createElement('mutation'); - container.setAttribute('mode', this.getFieldValue('MODE')); - return container; - }, - domToMutation: function(container) { - const mode = container.getAttribute('mode'); - if (mode) { - this.setFieldValue(mode, 'MODE'); - } - this.setSdMode(mode); - }, - setSdMode: function(mode) { - let connectedBlock = null; - - if (this.getInput('SIZE')) { - const valueConnection = this.getInput('SIZE').connection; - if (valueConnection) { - connectedBlock = valueConnection.targetBlock(); - } - this.removeInput('SIZE'); - } - if (this.getInput('VALUE')) { - this.removeInput('VALUE'); - } - if (mode === 'fwrite') { - // Ensure that the field only receives numeric data - this.appendValueInput('SIZE') - .setCheck('Number') - .appendField('SD file') - .appendField(new Blockly.FieldDropdown([ - ['write', 'fwrite'], - ['read', 'fread'], - ['close', 'fclose'], - ], function(mode) { - // eslint-disable-next-line no-invalid-this - this.getSourceBlock().setSdMode(mode); - }), 'MODE'); - this.appendValueInput('VALUE') - .setCheck('String') - .appendField('bytes of'); - } else if (mode === 'fread') { - this.appendValueInput('SIZE') - .setCheck('Number') - .appendField('SD file') - .appendField(new Blockly.FieldDropdown([ - ['read', 'fread'], - ['write', 'fwrite'], - ['close', 'fclose'], - ], function(mode) { - // eslint-disable-next-line no-invalid-this - this.getSourceBlock().setSdMode(mode); - }), 'MODE'); - this.appendDummyInput('VALUE') - .appendField('bytes store in') - .appendField(new Blockly.FieldVariable( - Blockly.LANG_VARIABLES_SET_ITEM), 'VAR'); - } else { - this.appendDummyInput('SIZE') - .appendField('SD file') - .appendField(new Blockly.FieldDropdown([ - ['close', 'fclose'], - ['read', 'fread'], - ['write', 'fwrite'], - ], function(mode) { - // eslint-disable-next-line no-invalid-this - this.getSourceBlock().setSdMode(mode); - }), 'MODE'); - } - if (connectedBlock) { - connectedBlock.outputConnection.connect(this.getInput('SIZE').connection); - } - }, - onchange: function(event) { - const project = getProjectInitialState(); - if (event.type === Blockly.Events.BLOCK_DELETE || - event.type === Blockly.Events.BLOCK_CREATE) { - let warnTxt = null; - const allBlocks = Blockly.getMainWorkspace().getAllBlocks().toString(); - if (allBlocks.indexOf('SD file open') === -1) { - warnTxt = 'WARNING: You must use a SD file open block\nbefore' + - ' reading, writing, or closing an SD file!'; - } else if (allBlocks.indexOf('SD initialize') === -1 && - project.boardType.name !== 'heb-wx' && - project.boardType.name !== 'activity-board') { - warnTxt = 'WARNING: You must use a SD initialize\nblock at the' + - ' beginning of your program!'; - } - this.setWarningText(warnTxt); - } - }, -}; - -/** - * SD Card Read/Write/Close C code generator - * - * Generate code to read from an sd card, write to an sd card or to close a - * connection to the sd card reader. - * - * @return {string} - */ -Blockly.propc.sd_read = function() { - // Identify the block action (fread, fwrite, or fclose) - const mode = this.getFieldValue('MODE'); - - // Handle close stright away - if (mode === 'fclose') { - return ` if(fp) ${mode}(fp);\r`; - } - - // Verify the required SD-Open block is in the project - const block = Blockly.getMainWorkspace().getBlocksByType( - 'sd_open', false); - - if ( block.length === 0 || (!block[0].isEnabled())) { - return '// WARNING: You must use a SD file open block before reading,' + - ' writing, or closing an SD file!\r'; - } - - /** - * Verify that for boards that do not have a built-in card reader, there is - * an sd_init block in the project - */ - const project = getProjectInitialState(); - let initFound = false; - - const initSdBlock = Blockly.getMainWorkspace().getBlocksByType( - 'sd_init', false); - if (initSdBlock.length > 0 && initSdBlock[0].isEnabled()) { - initFound = true; - } - - if (project.boardType.name !== 'heb-wx' && - project.boardType.name !== 'activity-board' && - ! initFound) { - return '/** WARNING: You must use a SD initialize block at the' + - ' beginning of your program! **/\r'; - } - - // Retrieve the number of bytes to read/write. Default to one byte - const size = Blockly.propc.valueToCode( - this, 'SIZE', Blockly.propc.ORDER_NONE) || '1'; - - let value = ''; - let code = ''; - - if (mode === 'fread') { - value = Blockly.propc.variableDB_.getName( - this.getFieldValue('VAR'), - Blockly.VARIABLE_CATEGORY_NAME); - - value = '&' + value; - Blockly.propc.vartype_[value] = 'char *'; - } else if (mode === 'fwrite') { - value = Blockly.propc.valueToCode( - this, 'VALUE', Blockly.propc.ORDER_NONE) || ''; - } - - code = ` ${mode}(${value}, 1, ${size}, fp);\r`; - - // Silently mount the embedded sd card device - const profile = getDefaultProfile(); - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; - } - - return code; -}; - -/** - * - * @type {{ - * init: Blockly.Blocks.sd_file_pointer.init, - * mutationToDom: *, - * helpUrl: string, - * setSdMode: Blockly.Blocks.sd_file_pointer.setSdMode, - * onchange: *, - * domToMutation: * - * }} - */ -Blockly.Blocks.sd_file_pointer = { - helpUrl: Blockly.MSG_SD_HELPURL, - init: function() { - this.setTooltip(Blockly.MSG_SD_FILE_POINTER_TOOLTIP); - this.setColour(colorPalette.getColor('output')); - this.setSdMode('set'); - this.setInputsInline(false); - this.setPreviousStatement(true, 'Block'); - this.setNextStatement(true, null); - }, - mutationToDom: Blockly.Blocks['sd_read'].mutationToDom, - domToMutation: Blockly.Blocks['sd_read'].domToMutation, - setSdMode: function(mode) { - if (this.getInput('FP')) { - this.removeInput('FP'); - } - if (mode === 'set') { - this.appendValueInput('FP') - .setCheck('Number') - .appendField('SD file') - .appendField(new Blockly.FieldDropdown([ - ['set', 'set'], - ['get', 'get'], - ], function(blockMode) { - // eslint-disable-next-line no-invalid-this - this.getSourceBlock().setSdMode(blockMode); - }), 'MODE') - .appendField('pointer = '); - this.setOutput(false); - this.setPreviousStatement(true, 'Block'); - this.setNextStatement(true, null); - } else { - // mode == get - this.appendDummyInput('FP'); - this.getInput('FP') - .appendField('SD file') - .appendField(new Blockly.FieldDropdown([ - ['get', 'get'], - ['set', 'set'], - ], function(blockMode) { - // eslint-disable-next-line no-invalid-this - this.getSourceBlock().setSdMode(blockMode); - }), 'MODE') - .appendField('pointer'); - - this.setPreviousStatement(false); - this.setNextStatement(false, null); - this.setOutput(true, 'Number'); - } - }, - onchange: Blockly.Blocks['sd_read'].onchange, -}; - -/** - * SD Card File Pointer - * @return {(string|number)[]|string} - */ -Blockly.propc.sd_file_pointer = function() { - const profile = getDefaultProfile(); - const project = getProjectInitialState(); - // TODO: Refactor getAllBlocks to getAllBlocksByType - const allBlocks = Blockly.getMainWorkspace().getAllBlocks().toString(); - let code = null; - let initFound = false; - for (let x = 0; x < allBlocks.length; x++) { - if (allBlocks[x].type === 'sd_init') { - initFound = true; - } - } - - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; - } - - if (allBlocks.indexOf('SD file open') === -1) { - code = '// WARNING: You must use a SD file open block before' + - ' using the file pointer!'; - } else if (allBlocks.indexOf('SD initialize') === -1 && - project.boardType.name !== 'heb-wx' && - project.boardType.name !== 'activity-board') { - code = '// WARNING: You must use a SD initialize block at the' + - ' beginning of your program!'; - } else if (this.getFieldValue('MODE') === 'set') { - const fp = Blockly.propc.valueToCode( - this, 'FP', Blockly.propc.ORDER_NONE) || '0'; - code = 'fp = ' + fp + ';\r'; - } else { - code = ['fp', Blockly.propc.ORDER_ATOMIC]; - } - return code; -}; // ----------------- Robot (drive) blocks ------------------------------------ diff --git a/src/modules/blockly/generators/propc/sd_card.js b/src/modules/blockly/generators/propc/sd_card.js new file mode 100644 index 00000000..e2972a19 --- /dev/null +++ b/src/modules/blockly/generators/propc/sd_card.js @@ -0,0 +1,467 @@ +/* + * TERMS OF USE: MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import Blockly from 'blockly/core'; +import {getDefaultProfile, getProjectInitialState} from '../../../project'; +import {colorPalette} from '../propc'; + +// ---------------------------------------------------------------- +// ----------------- SD Card file blocks -------------------------- +// ---------------------------------------------------------------- + + +/** + * SD Card Initialization + * @type {{ + * init: Blockly.Blocks.sd_init.init, + * helpUrl: string + * }} + */ +Blockly.Blocks.sd_init = { + helpUrl: Blockly.MSG_SD_HELPURL, + init: function() { + const profile = getDefaultProfile(); + this.setTooltip(Blockly.MSG_SD_INIT_TOOLTIP); + this.setColour(colorPalette.getColor('output')); + this.appendDummyInput() + .appendField('SD initialize DO') + .appendField(new Blockly.FieldDropdown( + profile.digital), 'DO') + .appendField('CLK') + .appendField(new Blockly.FieldDropdown( + profile.digital), 'CLK') + .appendField('DI') + .appendField(new Blockly.FieldDropdown( + profile.digital), 'DI') + .appendField('CS') + .appendField(new Blockly.FieldDropdown( + profile.digital), 'CS'), + this.setPreviousStatement(true, 'Block'); + this.setNextStatement(true, null); + }, +}; + +/** + * + * @return {string} + */ +Blockly.propc.sd_init = function() { + // Global variable for SD file processing + this.myType = 'fp'; + + if (!this.disabled) { + Blockly.propc.setups_['sd_card'] = 'sd_mount(' + + this.getFieldValue('DO') + ', ' + + this.getFieldValue('CLK') + ', ' + + this.getFieldValue('DI') + ', ' + + this.getFieldValue('CS') + ');'; + + // Declare the global variable + Blockly.propc.global_vars_[ + this.myType + 'global'] = 'FILE *' + this.myType + ';'; + } + + return ''; +}; + +/** + * + * @type {{ + * init: Blockly.Blocks.sd_open.init, + * helpUrl: string, + * onchange: Blockly.Blocks.sd_open.onchange + * }} + */ +Blockly.Blocks.sd_open = { + helpUrl: Blockly.MSG_SD_HELPURL, + init: function() { + this.setTooltip(Blockly.MSG_SD_OPEN_TOOLTIP); + this.setColour(colorPalette.getColor('output')); + this.appendDummyInput('MODE') + .appendField('SD file open') + .appendField(new Blockly.FieldTextInput( + 'filename.txt', + function(filename) { + filename = filename.replace(/[^A-Z0-9a-z_.]/g, '').toLowerCase(); + const filenamePart = filename.split('.'); + if (filenamePart[0].length > 8) { + filenamePart[0].length = 8; + } + if (!filenamePart[1]) { + filenamePart[1] = 'TXT'; + } else if (filenamePart[1].length > 3) { + filenamePart[1].length = 3; + } + return filenamePart[0] + '.' + filenamePart[1]; + }), 'FILENAME') + .appendField(new Blockly.FieldDropdown([ + ['as read-only', 'r'], + ['as read-write', 'w'], + ]), 'MODE'); + this.setInputsInline(false); + this.setPreviousStatement(true, 'Block'); + this.setNextStatement(true, null); + }, + + /** + * Check for an active sd_init block in the project. The block must exist + * and not be disabled. + */ + onchange: function() { + const project = getProjectInitialState(); + if (project.boardType.name !== 'activity-board' && + project.boardType.name !== 'heb-wx') { + const block = Blockly.getMainWorkspace().getBlocksByType( + 'sd_init', false); + if (block.length === 0 || ! block[0].isEnabled()) { + this.setWarningText('WARNING: You must use a SD' + + ' initialize\nblock at the beginning of your program!'); + } else { + this.setWarningText(null); + } + } + }, +}; + +/** + * SD Card Open C code generator + * @return {string} + */ +Blockly.propc.sd_open = function() { + const filename = this.getFieldValue('FILENAME'); + const mode = this.getFieldValue('MODE'); + let initFound = false; + + const initSdBlock = Blockly.getMainWorkspace().getBlocksByType( + 'sd_init', false); + if (initSdBlock.length > 0 && initSdBlock[0].isEnabled()) { + initFound = true; + } else { + const project = getProjectInitialState(); + if (project.boardType.name !== 'activity-board' && + project.boardType.name !== 'heb-wx') { + return '/** WARNING: You must use a SD initialize block at the' + + ' beginning of your program! **/\r'; + } + } + + // Quietly mount the sd card filesystem + const profile = getDefaultProfile(); + if (!this.disabled && !initFound && profile.sd_card) { + Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');\r'; + } + + return `fp = fopen("${filename}","${mode}");\r`; +}; + +/** + * + * @type {{ + * init: Blockly.Blocks.sd_read.init, + * mutationToDom: (function(): HTMLElement), + * helpUrl: string, + * setSdMode: Blockly.Blocks.sd_read.setSdMode, + * onchange: Blockly.Blocks.sd_read.onchange, + * domToMutation: Blockly.Blocks.sd_read.domToMutation + * }} + */ +Blockly.Blocks.sd_read = { + helpUrl: Blockly.MSG_SD_HELPURL, + init: function() { + this.setTooltip(Blockly.MSG_SD_READ_TOOLTIP); + this.setColour(colorPalette.getColor('output')); + this.setSdMode('fwrite'); + this.setInputsInline(true); + this.setPreviousStatement(true, 'Block'); + this.setNextStatement(true, null); + }, + mutationToDom: function() { + const container = document.createElement('mutation'); + container.setAttribute('mode', this.getFieldValue('MODE')); + return container; + }, + domToMutation: function(container) { + const mode = container.getAttribute('mode'); + if (mode) { + this.setFieldValue(mode, 'MODE'); + } + this.setSdMode(mode); + }, + setSdMode: function(mode) { + let connectedBlock = null; + + if (this.getInput('SIZE')) { + const valueConnection = this.getInput('SIZE').connection; + if (valueConnection) { + connectedBlock = valueConnection.targetBlock(); + } + this.removeInput('SIZE'); + } + if (this.getInput('VALUE')) { + this.removeInput('VALUE'); + } + if (mode === 'fwrite') { + // Ensure that the field only receives numeric data + this.appendValueInput('SIZE') + .setCheck('Number') + .appendField('SD file') + .appendField(new Blockly.FieldDropdown([ + ['write', 'fwrite'], + ['read', 'fread'], + ['close', 'fclose'], + ], function(mode) { + // eslint-disable-next-line no-invalid-this + this.getSourceBlock().setSdMode(mode); + }), 'MODE'); + this.appendValueInput('VALUE') + .setCheck('String') + .appendField('bytes of'); + } else if (mode === 'fread') { + this.appendValueInput('SIZE') + .setCheck('Number') + .appendField('SD file') + .appendField(new Blockly.FieldDropdown([ + ['read', 'fread'], + ['write', 'fwrite'], + ['close', 'fclose'], + ], function(mode) { + // eslint-disable-next-line no-invalid-this + this.getSourceBlock().setSdMode(mode); + }), 'MODE'); + this.appendDummyInput('VALUE') + .appendField('bytes store in') + .appendField(new Blockly.FieldVariable( + Blockly.LANG_VARIABLES_SET_ITEM), 'VAR'); + } else { + this.appendDummyInput('SIZE') + .appendField('SD file') + .appendField(new Blockly.FieldDropdown([ + ['close', 'fclose'], + ['read', 'fread'], + ['write', 'fwrite'], + ], function(mode) { + // eslint-disable-next-line no-invalid-this + this.getSourceBlock().setSdMode(mode); + }), 'MODE'); + } + if (connectedBlock) { + connectedBlock.outputConnection.connect(this.getInput('SIZE').connection); + } + }, + onchange: function(event) { + const project = getProjectInitialState(); + if (event.type === Blockly.Events.BLOCK_DELETE || + event.type === Blockly.Events.BLOCK_CREATE) { + let warnTxt = null; + const allBlocks = Blockly.getMainWorkspace().getAllBlocks().toString(); + if (allBlocks.indexOf('SD file open') === -1) { + warnTxt = 'WARNING: You must use a SD file open block\nbefore' + + ' reading, writing, or closing an SD file!'; + } else if (allBlocks.indexOf('SD initialize') === -1 && + project.boardType.name !== 'heb-wx' && + project.boardType.name !== 'activity-board') { + warnTxt = 'WARNING: You must use a SD initialize\nblock at the' + + ' beginning of your program!'; + } + this.setWarningText(warnTxt); + } + }, +}; + +/** + * SD Card Read/Write/Close C code generator + * + * Generate code to read from an sd card, write to an sd card or to close a + * connection to the sd card reader. + * + * @return {string} + */ +Blockly.propc.sd_read = function() { + // Identify the block action (fread, fwrite, or fclose) + const mode = this.getFieldValue('MODE'); + + // Handle close stright away + if (mode === 'fclose') { + return ` if(fp) ${mode}(fp);\r`; + } + + // Verify the required SD-Open block is in the project + const block = Blockly.getMainWorkspace().getBlocksByType( + 'sd_open', false); + + if ( block.length === 0 || (!block[0].isEnabled())) { + return '// WARNING: You must use a SD file open block before reading,' + + ' writing, or closing an SD file!\r'; + } + + /** + * Verify that for boards that do not have a built-in card reader, there is + * an sd_init block in the project + */ + const project = getProjectInitialState(); + let initFound = false; + + const initSdBlock = Blockly.getMainWorkspace().getBlocksByType( + 'sd_init', false); + if (initSdBlock.length > 0 && initSdBlock[0].isEnabled()) { + initFound = true; + } + + if (project.boardType.name !== 'heb-wx' && + project.boardType.name !== 'activity-board' && + ! initFound) { + return '/** WARNING: You must use a SD initialize block at the' + + ' beginning of your program! **/\r'; + } + + // Retrieve the number of bytes to read/write. Default to one byte + const size = Blockly.propc.valueToCode( + this, 'SIZE', Blockly.propc.ORDER_NONE) || '1'; + + let value = ''; + let code = ''; + + if (mode === 'fread') { + value = Blockly.propc.variableDB_.getName( + this.getFieldValue('VAR'), + Blockly.VARIABLE_CATEGORY_NAME); + + value = '&' + value; + Blockly.propc.vartype_[value] = 'char *'; + } else if (mode === 'fwrite') { + value = Blockly.propc.valueToCode( + this, 'VALUE', Blockly.propc.ORDER_NONE) || ''; + } + + code = ` ${mode}(${value}, 1, ${size}, fp);\r`; + + // Silently mount the embedded sd card device + const profile = getDefaultProfile(); + if (!this.disabled && !initFound && profile.sd_card) { + Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; + } + + return code; +}; + +/** + * + * @type {{ + * init: Blockly.Blocks.sd_file_pointer.init, + * mutationToDom: *, + * helpUrl: string, + * setSdMode: Blockly.Blocks.sd_file_pointer.setSdMode, + * onchange: *, + * domToMutation: * + * }} + */ +Blockly.Blocks.sd_file_pointer = { + helpUrl: Blockly.MSG_SD_HELPURL, + init: function() { + this.setTooltip(Blockly.MSG_SD_FILE_POINTER_TOOLTIP); + this.setColour(colorPalette.getColor('output')); + this.setSdMode('set'); + this.setInputsInline(false); + this.setPreviousStatement(true, 'Block'); + this.setNextStatement(true, null); + }, + mutationToDom: Blockly.Blocks['sd_read'].mutationToDom, + domToMutation: Blockly.Blocks['sd_read'].domToMutation, + setSdMode: function(mode) { + if (this.getInput('FP')) { + this.removeInput('FP'); + } + if (mode === 'set') { + this.appendValueInput('FP') + .setCheck('Number') + .appendField('SD file') + .appendField(new Blockly.FieldDropdown([ + ['set', 'set'], + ['get', 'get'], + ], function(blockMode) { + // eslint-disable-next-line no-invalid-this + this.getSourceBlock().setSdMode(blockMode); + }), 'MODE') + .appendField('pointer = '); + this.setOutput(false); + this.setPreviousStatement(true, 'Block'); + this.setNextStatement(true, null); + } else { + // mode == get + this.appendDummyInput('FP'); + this.getInput('FP') + .appendField('SD file') + .appendField(new Blockly.FieldDropdown([ + ['get', 'get'], + ['set', 'set'], + ], function(blockMode) { + // eslint-disable-next-line no-invalid-this + this.getSourceBlock().setSdMode(blockMode); + }), 'MODE') + .appendField('pointer'); + + this.setPreviousStatement(false); + this.setNextStatement(false, null); + this.setOutput(true, 'Number'); + } + }, + onchange: Blockly.Blocks['sd_read'].onchange, +}; + +/** + * SD Card File Pointer + * @return {(string|number)[]|string} + */ +Blockly.propc.sd_file_pointer = function() { + const profile = getDefaultProfile(); + const project = getProjectInitialState(); + // TODO: Refactor getAllBlocks to getAllBlocksByType + const allBlocks = Blockly.getMainWorkspace().getAllBlocks().toString(); + let code = null; + let initFound = false; + for (let x = 0; x < allBlocks.length; x++) { + if (allBlocks[x].type === 'sd_init') { + initFound = true; + } + } + + if (!this.disabled && !initFound && profile.sd_card) { + Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; + } + + if (allBlocks.indexOf('SD file open') === -1) { + code = '// WARNING: You must use a SD file open block before' + + ' using the file pointer!'; + } else if (allBlocks.indexOf('SD initialize') === -1 && + project.boardType.name !== 'heb-wx' && + project.boardType.name !== 'activity-board') { + code = '// WARNING: You must use a SD initialize block at the' + + ' beginning of your program!'; + } else if (this.getFieldValue('MODE') === 'set') { + const fp = Blockly.propc.valueToCode( + this, 'FP', Blockly.propc.ORDER_NONE) || '0'; + code = 'fp = ' + fp + ';\r'; + } else { + code = ['fp', Blockly.propc.ORDER_ATOMIC]; + } + return code; +}; diff --git a/src/modules/editor.js b/src/modules/editor.js index 8fd3cc58..2d817602 100644 --- a/src/modules/editor.js +++ b/src/modules/editor.js @@ -37,6 +37,7 @@ import './blockly/generators/propc/oled'; import './blockly/generators/propc/heb'; import './blockly/generators/propc/procedures'; import './blockly/generators/propc/s3'; +import './blockly/generators/propc/sd_card'; import './blockly/generators/propc/sensors'; import './blockly/generators/propc/variables'; From 25ea685e6b9d6a125e06c7bc2b0287ec1b31d4db Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 11:35:53 -0800 Subject: [PATCH 2/6] Refactor SD card open. Refactor sd_init into a separate function. --- .../blockly/generators/propc/sd_card.js | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/modules/blockly/generators/propc/sd_card.js b/src/modules/blockly/generators/propc/sd_card.js index e2972a19..905e5117 100644 --- a/src/modules/blockly/generators/propc/sd_card.js +++ b/src/modules/blockly/generators/propc/sd_card.js @@ -24,10 +24,6 @@ import Blockly from 'blockly/core'; import {getDefaultProfile, getProjectInitialState} from '../../../project'; import {colorPalette} from '../propc'; -// ---------------------------------------------------------------- -// ----------------- SD Card file blocks -------------------------- -// ---------------------------------------------------------------- - /** * SD Card Initialization @@ -61,6 +57,8 @@ Blockly.Blocks.sd_init = { }; /** + * Generate source code for the sd_init block. + * This creates a global file pointer. * * @return {string} */ @@ -147,29 +145,22 @@ Blockly.Blocks.sd_open = { * @return {string} */ Blockly.propc.sd_open = function() { - const filename = this.getFieldValue('FILENAME'); - const mode = this.getFieldValue('MODE'); - let initFound = false; - const initSdBlock = Blockly.getMainWorkspace().getBlocksByType( 'sd_init', false); - if (initSdBlock.length > 0 && initSdBlock[0].isEnabled()) { - initFound = true; - } else { + if (initSdBlock.length === 0 || !initSdBlock[0].isEnabled()) { const project = getProjectInitialState(); if (project.boardType.name !== 'activity-board' && project.boardType.name !== 'heb-wx') { return '/** WARNING: You must use a SD initialize block at the' + ' beginning of your program! **/\r'; + } else { + // Quietly mount the sd card filesystem + setupSdCard(); } } - // Quietly mount the sd card filesystem - const profile = getDefaultProfile(); - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');\r'; - } - + const filename = this.getFieldValue('FILENAME'); + const mode = this.getFieldValue('MODE'); return `fp = fopen("${filename}","${mode}");\r`; }; @@ -333,13 +324,17 @@ Blockly.propc.sd_read = function() { ' beginning of your program! **/\r'; } + // Silently mount the embedded sd card device + if (!this.disabled && !initFound) { + setupSdCard(); + } + // Retrieve the number of bytes to read/write. Default to one byte const size = Blockly.propc.valueToCode( this, 'SIZE', Blockly.propc.ORDER_NONE) || '1'; + // Retrieve the data buffer or variable let value = ''; - let code = ''; - if (mode === 'fread') { value = Blockly.propc.variableDB_.getName( this.getFieldValue('VAR'), @@ -352,15 +347,7 @@ Blockly.propc.sd_read = function() { this, 'VALUE', Blockly.propc.ORDER_NONE) || ''; } - code = ` ${mode}(${value}, 1, ${size}, fp);\r`; - - // Silently mount the embedded sd card device - const profile = getDefaultProfile(); - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; - } - - return code; + return ` ${mode}(${value}, 1, ${size}, fp);\r`; }; /** @@ -432,7 +419,6 @@ Blockly.Blocks.sd_file_pointer = { * @return {(string|number)[]|string} */ Blockly.propc.sd_file_pointer = function() { - const profile = getDefaultProfile(); const project = getProjectInitialState(); // TODO: Refactor getAllBlocks to getAllBlocksByType const allBlocks = Blockly.getMainWorkspace().getAllBlocks().toString(); @@ -444,24 +430,45 @@ Blockly.propc.sd_file_pointer = function() { } } - if (!this.disabled && !initFound && profile.sd_card) { - Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; + // Quietly install setup code + if (!this.disabled && !initFound) { + setupSdCard(); } if (allBlocks.indexOf('SD file open') === -1) { - code = '// WARNING: You must use a SD file open block before' + - ' using the file pointer!'; - } else if (allBlocks.indexOf('SD initialize') === -1 && + return '// WARNING: You must use a SD file open block before' + + ' using the file pointer!'; + } + if (allBlocks.indexOf('SD initialize') === -1 && project.boardType.name !== 'heb-wx' && project.boardType.name !== 'activity-board') { - code = '// WARNING: You must use a SD initialize block at the' + - ' beginning of your program!'; - } else if (this.getFieldValue('MODE') === 'set') { + return '// WARNING: You must use a SD initialize block at the' + + ' beginning of your program!'; + } + + if (this.getFieldValue('MODE') === 'set') { + // Set pointer const fp = Blockly.propc.valueToCode( this, 'FP', Blockly.propc.ORDER_NONE) || '0'; code = 'fp = ' + fp + ';\r'; + // fseek(fp, item, SEEK_CUR) + // code = `fp = (FILE*) fseek(${fp}, item, SEEK_CUR);\r`; } else { - code = ['fp', Blockly.propc.ORDER_ATOMIC]; + // Get pointer + code = ['ftell(fp);', Blockly.propc.ORDER_ATOMIC]; } + return code; }; + + +/** + * Mount SD Card + */ +function setupSdCard() { + const profile = getDefaultProfile(); + if (profile.sd_card) { + Blockly.propc.setups_['sd_card'] = 'sd_mount(' + profile.sd_card + ');'; + Blockly.propc.global_vars_['fpglobal'] = 'FILE *fp;'; + } +} From c169004c28254e733514e70af2f9f4a07820043d Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 11:49:29 -0800 Subject: [PATCH 3/6] Refactor warning messages. --- .../blockly/generators/propc/sd_card.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/modules/blockly/generators/propc/sd_card.js b/src/modules/blockly/generators/propc/sd_card.js index 905e5117..6676a674 100644 --- a/src/modules/blockly/generators/propc/sd_card.js +++ b/src/modules/blockly/generators/propc/sd_card.js @@ -24,6 +24,13 @@ import Blockly from 'blockly/core'; import {getDefaultProfile, getProjectInitialState} from '../../../project'; import {colorPalette} from '../propc'; +const SdInitMissingMessage = + '/** WARNING: You must use a SD initialize block at the' + + ' beginning of your program! **/\r'; + +const SdOpenMissingMessage = + '/** WARNING: You must use a SD file open block before reading,' + + ' writing, or closing an SD file! **/\r'; /** * SD Card Initialization @@ -151,8 +158,7 @@ Blockly.propc.sd_open = function() { const project = getProjectInitialState(); if (project.boardType.name !== 'activity-board' && project.boardType.name !== 'heb-wx') { - return '/** WARNING: You must use a SD initialize block at the' + - ' beginning of your program! **/\r'; + return SdOpenMissingMessage; } else { // Quietly mount the sd card filesystem setupSdCard(); @@ -300,8 +306,7 @@ Blockly.propc.sd_read = function() { 'sd_open', false); if ( block.length === 0 || (!block[0].isEnabled())) { - return '// WARNING: You must use a SD file open block before reading,' + - ' writing, or closing an SD file!\r'; + return SdOpenMissingMessage; } /** @@ -320,8 +325,7 @@ Blockly.propc.sd_read = function() { if (project.boardType.name !== 'heb-wx' && project.boardType.name !== 'activity-board' && ! initFound) { - return '/** WARNING: You must use a SD initialize block at the' + - ' beginning of your program! **/\r'; + return SdInitMissingMessage; } // Silently mount the embedded sd card device @@ -442,8 +446,7 @@ Blockly.propc.sd_file_pointer = function() { if (allBlocks.indexOf('SD initialize') === -1 && project.boardType.name !== 'heb-wx' && project.boardType.name !== 'activity-board') { - return '// WARNING: You must use a SD initialize block at the' + - ' beginning of your program!'; + return SdInitMissingMessage; } if (this.getFieldValue('MODE') === 'set') { From f40945aeb32687b95444af2de128daff015066b6 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 17:36:30 -0800 Subject: [PATCH 4/6] Replace '\r' with '\n'. Remove semicolon from get file pointer block. --- .../blockly/generators/propc/sd_card.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/modules/blockly/generators/propc/sd_card.js b/src/modules/blockly/generators/propc/sd_card.js index 6676a674..d7119f9f 100644 --- a/src/modules/blockly/generators/propc/sd_card.js +++ b/src/modules/blockly/generators/propc/sd_card.js @@ -26,11 +26,11 @@ import {colorPalette} from '../propc'; const SdInitMissingMessage = '/** WARNING: You must use a SD initialize block at the' + - ' beginning of your program! **/\r'; + ' beginning of your program! **/\n'; const SdOpenMissingMessage = '/** WARNING: You must use a SD file open block before reading,' + - ' writing, or closing an SD file! **/\r'; + ' writing, or closing an SD file! **/\n'; /** * SD Card Initialization @@ -167,7 +167,7 @@ Blockly.propc.sd_open = function() { const filename = this.getFieldValue('FILENAME'); const mode = this.getFieldValue('MODE'); - return `fp = fopen("${filename}","${mode}");\r`; + return `fp = fopen("${filename}","${mode}");\n`; }; /** @@ -298,7 +298,7 @@ Blockly.propc.sd_read = function() { // Handle close stright away if (mode === 'fclose') { - return ` if(fp) ${mode}(fp);\r`; + return `if(fp) ${mode}(fp);\n`; } // Verify the required SD-Open block is in the project @@ -351,7 +351,7 @@ Blockly.propc.sd_read = function() { this, 'VALUE', Blockly.propc.ORDER_NONE) || ''; } - return ` ${mode}(${value}, 1, ${size}, fp);\r`; + return `${mode}(${value}, 1, ${size}, fp);\n`; }; /** @@ -441,7 +441,7 @@ Blockly.propc.sd_file_pointer = function() { if (allBlocks.indexOf('SD file open') === -1) { return '// WARNING: You must use a SD file open block before' + - ' using the file pointer!'; + ' using the file pointer!\n'; } if (allBlocks.indexOf('SD initialize') === -1 && project.boardType.name !== 'heb-wx' && @@ -453,12 +453,10 @@ Blockly.propc.sd_file_pointer = function() { // Set pointer const fp = Blockly.propc.valueToCode( this, 'FP', Blockly.propc.ORDER_NONE) || '0'; - code = 'fp = ' + fp + ';\r'; - // fseek(fp, item, SEEK_CUR) - // code = `fp = (FILE*) fseek(${fp}, item, SEEK_CUR);\r`; + code = `fp = (FILE*) fseek(fp, ${fp}, SEEK_CUR);\n`; } else { // Get pointer - code = ['ftell(fp);', Blockly.propc.ORDER_ATOMIC]; + code = ['ftell(fp)', Blockly.propc.ORDER_ATOMIC]; } return code; From a59b1017c157a33bf7299c87c4f18654b14662c8 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 17:36:58 -0800 Subject: [PATCH 5/6] Add SD File reserved words. --- src/modules/blockly/generators/propc.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/blockly/generators/propc.js b/src/modules/blockly/generators/propc.js index c2958e2a..22deaff3 100644 --- a/src/modules/blockly/generators/propc.js +++ b/src/modules/blockly/generators/propc.js @@ -399,6 +399,12 @@ Blockly.propc.addReservedWords( 'ws2812_set,ws2812_start,ws2812_stop,ws2812_wheel,ws2812_wheel_dim,' + 'ws2812b_open,ws2812b_start'); +/** + * SD File reserved words + */ +Blockly.propc.addReservedWords( + 'fp,fclose,fopen,fread,fseek,ftell,fwrite,sd_init,sd_mount,'); + /** * Order of operation ENUMs. * From 468acb5843652341aae5820ffe3c7f322e4130fd Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Sat, 16 Jan 2021 22:09:45 -0800 Subject: [PATCH 6/6] Correct error in set file pointer. --- src/modules/blockly/generators/propc/sd_card.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/modules/blockly/generators/propc/sd_card.js b/src/modules/blockly/generators/propc/sd_card.js index d7119f9f..65880933 100644 --- a/src/modules/blockly/generators/propc/sd_card.js +++ b/src/modules/blockly/generators/propc/sd_card.js @@ -420,7 +420,16 @@ Blockly.Blocks.sd_file_pointer = { /** * SD Card File Pointer + * Retrieves or sets the file pointer of an open file. + * + * set - Uses the fseek function to position the file pointer to 'n' bytes + * from the beginning of the file. + * + * get - Returns an integer value indicating the current position of the + * file pointer in the file stream. + * * @return {(string|number)[]|string} + * */ Blockly.propc.sd_file_pointer = function() { const project = getProjectInitialState(); @@ -443,6 +452,7 @@ Blockly.propc.sd_file_pointer = function() { return '// WARNING: You must use a SD file open block before' + ' using the file pointer!\n'; } + if (allBlocks.indexOf('SD initialize') === -1 && project.boardType.name !== 'heb-wx' && project.boardType.name !== 'activity-board') { @@ -450,10 +460,9 @@ Blockly.propc.sd_file_pointer = function() { } if (this.getFieldValue('MODE') === 'set') { - // Set pointer const fp = Blockly.propc.valueToCode( this, 'FP', Blockly.propc.ORDER_NONE) || '0'; - code = `fp = (FILE*) fseek(fp, ${fp}, SEEK_CUR);\n`; + code = `fseek(fp, ${fp}, SEEK_SET);\n`; } else { // Get pointer code = ['ftell(fp)', Blockly.propc.ORDER_ATOMIC];