| | |
| | <!DOCTYPE html> |
| | <html lang="ja"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Arduinoビジュアルプログラミング</title> |
| | <style> |
| | body { |
| | font-family: Arial, sans-serif; |
| | margin: 0; |
| | padding: 20px; |
| | background-color: #f0f0f0; |
| | } |
| | |
| | .container { |
| | display: flex; |
| | gap: 20px; |
| | max-width: 1200px; |
| | margin: 0 auto; |
| | align-items: stretch; |
| | } |
| | |
| | #block-area { |
| | width: 60%; |
| | height: 500px; |
| | background-color: #fff; |
| | border: 2px solid #ccc; |
| | border-radius: 5px; |
| | position: relative; |
| | } |
| | |
| | #code-area { |
| | width: 40%; |
| | height: 500px; |
| | background-color: #333; |
| | color: #fff; |
| | border-radius: 5px; |
| | padding: 10px; |
| | overflow-y: auto; |
| | font-family: monospace; |
| | box-sizing: border-box; |
| | position: relative; |
| | } |
| | |
| | #copy-button { |
| | position: absolute; |
| | top: 10px; |
| | right: 10px; |
| | cursor: pointer; |
| | } |
| | |
| | #copy-message { |
| | position: absolute; |
| | top: 40px; |
| | right: 10px; |
| | background-color: rgba(0, 0, 0, 0.7); |
| | color: #fff; |
| | padding: 5px 10px; |
| | border-radius: 3px; |
| | font-size: 12px; |
| | display: none; |
| | } |
| | |
| | .highlight { |
| | background-color: #FFFF99 !important; |
| | color: #000 !important; |
| | } |
| | |
| | .button-container { |
| | max-width: 1200px; |
| | margin: 20px auto 0; |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | } |
| | |
| | .left-buttons { |
| | display: flex; |
| | gap: 10px; |
| | } |
| | |
| | .right-buttons { |
| | display: flex; |
| | gap: 10px; |
| | } |
| | |
| | button { |
| | padding: 10px 20px; |
| | font-size: 16px; |
| | border: none; |
| | border-radius: 5px; |
| | cursor: pointer; |
| | } |
| | |
| | #save-btn { |
| | background-color: #28a745; |
| | color: white; |
| | } |
| | |
| | #save-btn:hover { |
| | background-color: #218838; |
| | } |
| | |
| | #clear-btn { |
| | background-color: #dc3545; |
| | color: white; |
| | } |
| | |
| | #clear-btn:hover { |
| | background-color: #b02a37; |
| | } |
| | |
| | #download-btn { |
| | background-color: #007bff; |
| | color: white; |
| | } |
| | |
| | #download-btn:hover { |
| | background-color: #0056b3; |
| | } |
| | |
| | #print-btn { |
| | background-color: #ffc107; |
| | color: black; |
| | } |
| | |
| | #print-btn:hover { |
| | background-color: #e0a800; |
| | } |
| | |
| | #exit-btn { |
| | background-color: #6c757d; |
| | color: white; |
| | } |
| | |
| | #exit-btn:hover { |
| | background-color: #5a6268; |
| | } |
| | |
| | |
| | .blocklyZoom { |
| | position: absolute; |
| | bottom: 100px; |
| | right: 43px; |
| | display: flex; |
| | flex-direction: column; |
| | gap: 2px; |
| | z-index: 10; |
| | } |
| | |
| | .blocklyZoom svg { |
| | width: 32px; |
| | height: 32px; |
| | cursor: pointer; |
| | } |
| | |
| | |
| | .blocklyTrash { |
| | bottom: 10px !important; |
| | right: 10px !important; |
| | } |
| | |
| | #serial-btn { |
| | background-color: #17a2b8; |
| | color: white; |
| | } |
| | |
| | #serial-btn:hover { |
| | background-color: #138496; |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <div class="container"> |
| | <div id="block-area"></div> |
| | <div id="code-area"> |
| | <img id="copy-button" src="copy.png" alt="Copy Code" title="コードをコピー"> |
| | <div id="copy-message">クリップボードにコピーしました</div> |
| | <pre id="generated-code">// 生成されたArduinoコードがここに表示されます</pre> |
| | </div> |
| | </div> |
| | <div class="button-container"> |
| | <div class="left-buttons"> |
| | <button id="download-btn">ダウンロード</button> |
| | <button id="serial-btn">シリアル通信</button> |
| | <button id="clear-btn">クリア</button> |
| | </div> |
| | <div class="right-buttons"> |
| | </div> |
| | </div> |
| |
|
| | <div id="serial-modal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;"> |
| | <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 875px; height: 400px; background: #fff; border-radius: 5px; overflow: hidden;"> |
| | <button id="close-modal" style="position: absolute; top: 10px; right: 10px; font-size: 20px; border: none; background: #fff; color: black; width: 30px; height: 30px; border-radius: 5px; cursor: pointer;">×</button> |
| | <iframe id="serial-iframe" src="" style="width: 100%; height: calc(100% - 50px); margin-top: 50px; border: none;"></iframe> |
| | </div> |
| | </div> |
| |
|
| | |
| | <xml id="toolbox" style="display: none"> |
| | <category name="制御" colour="120"> |
| | <block type="setup"></block> |
| | <block type="loop"></block> |
| | <block type="delay"> |
| | <value name="TIME"> |
| | <shadow type="math_number"> |
| | <field name="NUM">1000</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="delay_value"> |
| | <value name="TIME"> |
| | <shadow type="math_number"> |
| | <field name="NUM">1000</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="delay_microseconds"> |
| | <value name="TIME"> |
| | <shadow type="math_number"> |
| | <field name="NUM">100</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="delay_microseconds_value"> |
| | <value name="TIME"> |
| | <shadow type="math_number"> |
| | <field name="NUM">100</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="controls_while"></block> |
| | <block type="controls_if"></block> |
| | <block type="repeat_times"> |
| | <value name="TIMES"> |
| | <shadow type="math_number"> |
| | <field name="NUM">5</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="if_condition"></block> |
| | <block type="wait_until_condition"></block> |
| | </category> |
| | <category name="ピン" colour="160"> |
| | <block type="pin_mode"> |
| | <value name="PIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">13</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="digital_write"> |
| | <value name="PIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">13</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="digital_read"> |
| | <value name="PIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">13</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="analog_read"></block> |
| | <block type="analog_write"> |
| | <value name="PIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">9</field> |
| | </shadow> |
| | </value> |
| | <value name="VALUE"> |
| | <shadow type="math_number"> |
| | <field name="NUM">255</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | </category> |
| | <category name="テスト" colour="210"> |
| | <block type="logic_compare"></block> |
| | <block type="logic_operation"></block> |
| | <block type="string_compare"> |
| | <value name="A"> |
| | <shadow type="text"> |
| | <field name="TEXT">text1</field> |
| | </shadow> |
| | </value> |
| | <value name="B"> |
| | <shadow type="text"> |
| | <field name="TEXT">text2</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | </category> |
| | <category name="計算" colour="230"> |
| | <block type="math_arithmetic"></block> |
| | <block type="math_single"></block> |
| | <block type="math_trig"></block> |
| | <block type="random_number"> |
| | <value name="MIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">0</field> |
| | </shadow> |
| | </value> |
| | <value name="MAX"> |
| | <shadow type="math_number"> |
| | <field name="NUM">100</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="divide"> |
| | <value name="NUM"> |
| | <shadow type="math_number"> |
| | <field name="NUM">10</field> |
| | </shadow> |
| | </value> |
| | <value name="DIV"> |
| | <shadow type="math_number"> |
| | <field name="NUM">2</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="number_input"> |
| | <field name="VALUE">0</field> |
| | </block> |
| | <block type="string_input"> |
| | <field name="TEXT">Hello</field> |
| | </block> |
| | <block type="text_input"> |
| | <field name="TEXT">Hello</field> |
| | </block> |
| | </category> |
| | <category name="変数" colour="260"> |
| | <block type="variable_declare_int"></block> |
| | <block type="variable_set_int"></block> |
| | <block type="variable_get_int"></block> |
| | <block type="int_declare"></block> |
| | <block type="int_set"></block> |
| | <block type="int_get"></block> |
| | <block type="float_declare"></block> |
| | <block type="float_set"></block> |
| | <block type="float_get"></block> |
| | </category> |
| | <category name="Generic Hardware" colour="290"> |
| | <block type="servo_write"> |
| | <value name="PIN"> |
| | <shadow type="math_number"> |
| | <field name="NUM">9</field> |
| | </shadow> |
| | </value> |
| | <value name="ANGLE"> |
| | <shadow type="math_number"> |
| | <field name="NUM">90</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="ultrasonic_read"></block> |
| | <block type="ultrasonic_distance"></block> |
| | <block type="lcd_print"> |
| | <value name="TEXT"> |
| | <shadow type="text"> |
| | <field name="TEXT">Hello World!!</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="lcd_print_value"> |
| | <value name="VALUE"> |
| | <shadow type="math_number"> |
| | <field name="NUM">0</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="lcd_clear"></block> |
| | <block type="seven_segment_display"> |
| | <value name="NUMBER"> |
| | <shadow type="math_number"> |
| | <field name="NUM">0</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="tone"> |
| | <value name="FREQUENCY"> |
| | <shadow type="math_number"> |
| | <field name="NUM">440</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="noTone"></block> |
| | </category> |
| | <category name="通信" colour="320"> |
| | <block type="serial_begin"></block> |
| | <block type="serial_print"> |
| | <value name="TEXT"> |
| | <shadow type="text"> |
| | <field name="TEXT">Hello</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="serial_print_value"> |
| | <value name="VALUE"> |
| | <shadow type="math_number"> |
| | <field name="NUM">0</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="serial_println"> |
| | <value name="TEXT"> |
| | <shadow type="text"> |
| | <field name="TEXT">Hello</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="serial_println_value"> |
| | <value name="VALUE"> |
| | <shadow type="math_number"> |
| | <field name="NUM">0</field> |
| | </shadow> |
| | </value> |
| | </block> |
| | <block type="serial_read_number"></block> |
| | <block type="serial_read_string"></block> |
| | </category> |
| | <category name="拡張" colour="350"> |
| | <block type="custom_code"></block> |
| | <block type="custom_string"></block> |
| | <block type="custom_number"></block> |
| | </category> |
| | </xml> |
| |
|
| | |
| | <script src="./blockly.min.js"></script> |
| | |
| | <script src="./ja.js"></script> |
| | |
| | <script src="./pako.min.js"></script> |
| | |
| | <script src="html2canvas.min.js"></script> |
| |
|
| | <script> |
| | // 文字列をクリーンアップする関数 |
| | function cleanString(str) { |
| | if (!str) return '""'; |
| | let cleaned = str.replace(/^\s*\(?['"]?(.*?)['"]?\)?\s*$/, '$1'); |
| | if (cleaned === '') return '""'; |
| | if (!cleaned.startsWith('"') || !cleaned.endsWith('"')) { |
| | cleaned = `"${cleaned.replace(/"/g, '\\"')}"`; |
| | } |
| | return cleaned; |
| | } |
| | |
| | // 7セグメントLEDの数字マッピング(カソードコモン、HIGH=点灯) |
| | const segmentPatterns = [ |
| | [1, 1, 1, 1, 1, 1, 0], // 0 |
| | [0, 1, 1, 0, 0, 0, 0], // 1 |
| | [1, 1, 0, 1, 1, 0, 1], // 2 |
| | [1, 1, 1, 1, 0, 0, 1], // 3 |
| | [0, 1, 1, 0, 0, 1, 1], // 4 |
| | [1, 0, 1, 1, 0, 1, 1], // 5 |
| | [1, 0, 1, 1, 1, 1, 1], // 6 |
| | [1, 1, 1, 0, 0, 0, 0], // 7 |
| | [1, 1, 1, 1, 1, 1, 1], // 8 |
| | [1, 1, 1, 1, 0, 1, 1] // 9 |
| | ]; |
| | |
| | // カスタムブロックの定義 |
| | // 制御 |
| | Blockly.Blocks['setup'] = { |
| | init: function () { |
| | this.appendStatementInput('SETUP_CODE').appendField('セットアップ'); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['loop'] = { |
| | init: function () { |
| | this.appendStatementInput('LOOP_CODE').appendField('ループ'); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['delay'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('待機:') |
| | .appendField(new Blockly.FieldNumber(1000, 0), 'TIME') |
| | .appendField('ms'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['delay_value'] = { |
| | init: function () { |
| | this.appendValueInput('TIME') |
| | .setCheck('Number') |
| | .appendField('待機:'); |
| | this.appendDummyInput() |
| | .appendField('ms'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['delay_microseconds'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('待機:') |
| | .appendField(new Blockly.FieldNumber(100, 0), 'TIME') |
| | .appendField('μs'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['delay_microseconds_value'] = { |
| | init: function () { |
| | this.appendValueInput('TIME') |
| | .setCheck('Number') |
| | .appendField('待機:'); |
| | this.appendDummyInput() |
| | .appendField('μs'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['controls_while'] = { |
| | init: function () { |
| | this.appendValueInput('CONDITION').appendField('条件が真の間繰り返す'); |
| | this.appendStatementInput('DO').appendField('実行'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['controls_if'] = { |
| | init: function () { |
| | this.appendValueInput('IF0').appendField('もし'); |
| | this.appendStatementInput('DO0').appendField('なら'); |
| | this.appendStatementInput('ELSE').appendField('でなければ'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['repeat_times'] = { |
| | init: function () { |
| | this.appendValueInput('TIMES') |
| | .setCheck('Number') |
| | .appendField('繰り返し:'); |
| | this.appendStatementInput('DO') |
| | .appendField('回'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['if_condition'] = { |
| | init: function () { |
| | this.appendValueInput('CONDITION') |
| | .setCheck('Boolean') |
| | .appendField('もし'); |
| | this.appendStatementInput('DO') |
| | .appendField('なら'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | Blockly.Blocks['wait_until_condition'] = { |
| | init: function () { |
| | this.appendValueInput('CONDITION') |
| | .setCheck('Boolean') |
| | .appendField('条件が真になるまで待つ'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(120); |
| | } |
| | }; |
| | |
| | // ピン |
| | Blockly.Blocks['pin_mode'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('ピンのモードを設定:') |
| | .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN') |
| | .appendField(new Blockly.FieldDropdown([['出力', 'OUTPUT'], ['入力', 'INPUT'], ['入力プルアップ', 'INPUT_PULLUP']]), 'MODE'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(160); |
| | } |
| | }; |
| | Blockly.Blocks['digital_write'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('デジタル出力:') |
| | .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN') |
| | .appendField(new Blockly.FieldDropdown([['HIGH', 'HIGH'], ['LOW', 'LOW']]), 'VALUE'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(160); |
| | } |
| | }; |
| | Blockly.Blocks['digital_read'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('デジタル入力:') |
| | .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(160); |
| | } |
| | }; |
| | Blockly.Blocks['analog_read'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('アナログ入力:') |
| | .appendField(new Blockly.FieldDropdown([ |
| | ['A0', 'A0'], ['A1', 'A1'], ['A2', 'A2'], ['A3', 'A3'], |
| | ['A4', 'A4'], ['A5', 'A5'], ['A6', 'A6'], ['A7', 'A7'], |
| | ['A8', 'A8'], ['A9', 'A9'], ['A10', 'A10'], ['A11', 'A11'], |
| | ['A12', 'A12'], ['A13', 'A13'], ['A14', 'A14'], ['A15', 'A15'] |
| | ]), 'PIN'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(160); |
| | } |
| | }; |
| | Blockly.Blocks['analog_write'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('アナログ出力:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN'); |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('値:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(160); |
| | } |
| | }; |
| | |
| | // テスト |
| | Blockly.Blocks['logic_compare'] = { |
| | init: function () { |
| | this.appendValueInput('A').setCheck('Number'); |
| | this.appendDummyInput() |
| | .appendField(new Blockly.FieldDropdown([['=', 'EQ'], ['≠', 'NEQ'], ['<', 'LT'], ['≤', 'LTE'], ['>', 'GT'], ['≥', 'GTE']]), 'OP'); |
| | this.appendValueInput('B').setCheck('Number'); |
| | this.setOutput(true, 'Boolean'); |
| | this.setColour(210); |
| | } |
| | }; |
| | Blockly.Blocks['logic_operation'] = { |
| | init: function () { |
| | this.appendValueInput('A').setCheck('Boolean'); |
| | this.appendDummyInput() |
| | .appendField(new Blockly.FieldDropdown([['かつ', 'AND'], ['または', 'OR']]), 'OP'); |
| | this.appendValueInput('B').setCheck('Boolean'); |
| | this.setOutput(true, 'Boolean'); |
| | this.setColour(210); |
| | } |
| | }; |
| | Blockly.Blocks['string_compare'] = { |
| | init: function () { |
| | this.appendValueInput('A').setCheck('String'); |
| | this.appendDummyInput() |
| | .appendField(new Blockly.FieldDropdown([['=', 'EQ'], ['≠', 'NEQ']]), 'OP'); |
| | this.appendValueInput('B').setCheck('String'); |
| | this.setOutput(true, 'Boolean'); |
| | this.setColour(210); |
| | } |
| | }; |
| | |
| | // 計算 |
| | Blockly.Blocks['math_arithmetic'] = { |
| | init: function () { |
| | this.appendValueInput('A').setCheck('Number'); |
| | this.appendDummyInput() |
| | .appendField(new Blockly.FieldDropdown([['+', 'ADD'], ['-', 'MINUS'], ['×', 'MULTIPLY'], ['÷', 'DIVIDE']]), 'OP'); |
| | this.appendValueInput('B').setCheck('Number'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['math_single'] = { |
| | init: function () { |
| | this.appendValueInput('NUM').setCheck('Number') |
| | .appendField(new Blockly.FieldDropdown([['絶対値', 'ABS'], ['平方根', 'SQRT']]), 'OP'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['math_trig'] = { |
| | init: function () { |
| | this.appendValueInput('NUM').setCheck('Number') |
| | .appendField(new Blockly.FieldDropdown([['sin', 'SIN'], ['cos', 'COS'], ['tan', 'TAN']]), 'OP'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['random_number'] = { |
| | init: function () { |
| | this.appendValueInput('MIN') |
| | .setCheck('Number') |
| | .appendField('乱数:'); |
| | this.appendValueInput('MAX') |
| | .setCheck('Number') |
| | .appendField('から'); |
| | this.appendDummyInput() |
| | .appendField('まで'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['divide'] = { |
| | init: function () { |
| | this.appendValueInput('NUM') |
| | .setCheck('Number') |
| | .appendField(''); |
| | this.appendValueInput('DIV') |
| | .setCheck('Number') |
| | .appendField('を'); |
| | this.appendDummyInput() |
| | .appendField('で割った値'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['number_input'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('数値:') |
| | .appendField(new Blockly.FieldNumber(0), 'VALUE'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['string_input'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('文字列:') |
| | .appendField(new Blockly.FieldTextInput('Hello'), 'TEXT'); |
| | this.setOutput(true, 'String'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['text_input'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('テキスト:') |
| | .appendField(new Blockly.FieldTextInput('Hello'), 'TEXT'); |
| | this.setOutput(true, 'String'); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['variable_set_number'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('数値変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR') |
| | .appendField('に代入:'); |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(230); |
| | } |
| | }; |
| | Blockly.Blocks['variable_set_string'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('文字列変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR') |
| | .appendField('に代入:'); |
| | this.appendValueInput('TEXT') |
| | .setCheck('String'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(230); |
| | } |
| | }; |
| | |
| | // 変数 |
| | Blockly.Blocks['variable_declare_int'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('整数変数宣言:') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['variable_set_int'] = { |
| | init: function () { |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('整数変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR') |
| | .appendField('に代入:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['variable_get_int'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('整数変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['int_declare'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('int変数宣言:') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['int_set'] = { |
| | init: function () { |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('int変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR') |
| | .appendField('に代入:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['int_get'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('int変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['float_declare'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('float変数宣言:') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['float_set'] = { |
| | init: function () { |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('float変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR') |
| | .appendField('に代入:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(260); |
| | } |
| | }; |
| | Blockly.Blocks['float_get'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('float変数') |
| | .appendField(new Blockly.FieldVariable(null), 'VAR'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(260); |
| | } |
| | }; |
| | |
| | // Generic Hardware |
| | Blockly.Blocks['servo_write'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('サーボ:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN'); |
| | this.appendValueInput('ANGLE') |
| | .setCheck('Number') |
| | .appendField('角度:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['ultrasonic_read'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('超音波センサ: トリガ') |
| | .appendField(new Blockly.FieldNumber(12, 0, 53), 'TRIG') |
| | .appendField('エコー') |
| | .appendField(new Blockly.FieldNumber(11, 0, 53), 'ECHO'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['ultrasonic_distance'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('超音波センサ') |
| | .appendField('トリガ') |
| | .appendField(new Blockly.FieldNumber(12, 0, 53), 'TRIG'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['lcd_print'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('LCD表示 ピン RS:') |
| | .appendField(new Blockly.FieldNumber(8, 0, 53), 'RS') |
| | .appendField('E:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'E') |
| | .appendField('D4:') |
| | .appendField(new Blockly.FieldNumber(4, 0, 53), 'D4'); |
| | this.appendDummyInput() |
| | .appendField('D5:') |
| | .appendField(new Blockly.FieldNumber(5, 0, 53), 'D5') |
| | .appendField('D6:') |
| | .appendField(new Blockly.FieldNumber(6, 0, 53), 'D6') |
| | .appendField('D7:') |
| | .appendField(new Blockly.FieldNumber(7, 0, 53), 'D7'); |
| | this.appendDummyInput() |
| | .appendField('列数:') |
| | .appendField(new Blockly.FieldNumber(16, 1), 'COLS') |
| | .appendField('行数:') |
| | .appendField(new Blockly.FieldNumber(2, 1), 'ROWS'); |
| | this.appendDummyInput() |
| | .appendField('カーソル 列:') |
| | .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_COL') |
| | .appendField('行:') |
| | .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_ROW'); |
| | this.appendValueInput('TEXT') |
| | .appendField('テキスト:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['lcd_print_value'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('LCD数値表示 ピン RS:') |
| | .appendField(new Blockly.FieldNumber(8, 0, 53), 'RS') |
| | .appendField('E:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'E') |
| | .appendField('D4:') |
| | .appendField(new Blockly.FieldNumber(4, 0, 53), 'D4'); |
| | this.appendDummyInput() |
| | .appendField('D5:') |
| | .appendField(new Blockly.FieldNumber(5, 0, 53), 'D5') |
| | .appendField('D6:') |
| | .appendField(new Blockly.FieldNumber(6, 0, 53), 'D6') |
| | .appendField('D7:') |
| | .appendField(new Blockly.FieldNumber(7, 0, 53), 'D7'); |
| | this.appendDummyInput() |
| | .appendField('列数:') |
| | .appendField(new Blockly.FieldNumber(16, 1), 'COLS') |
| | .appendField('行数:') |
| | .appendField(new Blockly.FieldNumber(2, 1), 'ROWS'); |
| | this.appendDummyInput() |
| | .appendField('カーソル 列:') |
| | .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_COL') |
| | .appendField('行:') |
| | .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_ROW'); |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('数値:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['lcd_clear'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('LCDクリア'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['seven_segment_display'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('7セグメントLED表示 ピン a:') |
| | .appendField(new Blockly.FieldNumber(2, 0, 53), 'PIN_A') |
| | .appendField('b:') |
| | .appendField(new Blockly.FieldNumber(3, 0, 53), 'PIN_B') |
| | .appendField('c:') |
| | .appendField(new Blockly.FieldNumber(4, 0, 53), 'PIN_C'); |
| | this.appendDummyInput() |
| | .appendField('d:') |
| | .appendField(new Blockly.FieldNumber(5, 0, 53), 'PIN_D') |
| | .appendField('e:') |
| | .appendField(new Blockly.FieldNumber(6, 0, 53), 'PIN_E') |
| | .appendField('f:') |
| | .appendField(new Blockly.FieldNumber(7, 0, 53), 'PIN_F'); |
| | this.appendDummyInput() |
| | .appendField('g:') |
| | .appendField(new Blockly.FieldNumber(8, 0, 53), 'PIN_G'); |
| | this.appendValueInput('NUMBER') |
| | .setCheck('Number') |
| | .appendField('数字:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['tone'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('トーン出力 ピン:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN'); |
| | this.appendValueInput('FREQUENCY') |
| | .setCheck('Number') |
| | .appendField('周波数(Hz):'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | Blockly.Blocks['noTone'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('トーン停止 ピン:') |
| | .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(290); |
| | } |
| | }; |
| | |
| | // 通信 |
| | Blockly.Blocks['serial_begin'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('シリアル開始:') |
| | .appendField(new Blockly.FieldNumber(9600), 'BAUD'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_print'] = { |
| | init: function () { |
| | this.appendValueInput('TEXT') |
| | .appendField('シリアル出力(改行なし):'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_print_value'] = { |
| | init: function () { |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('シリアル出力(数値、改行なし):'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_println'] = { |
| | init: function () { |
| | this.appendValueInput('TEXT') |
| | .appendField('シリアル出力:'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_println_value'] = { |
| | init: function () { |
| | this.appendValueInput('VALUE') |
| | .setCheck('Number') |
| | .appendField('シリアル出力(数値):'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_read_number'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('シリアル入力(数値)'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(320); |
| | } |
| | }; |
| | Blockly.Blocks['serial_read_string'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('シリアル入力(文字列)'); |
| | this.setOutput(true, 'String'); |
| | this.setColour(320); |
| | } |
| | }; |
| | |
| | // 拡張 |
| | Blockly.Blocks['custom_code'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('カスタムコード:') |
| | .appendField(new Blockly.FieldTextInput(''), 'CODE'); |
| | this.setPreviousStatement(true); |
| | this.setNextStatement(true); |
| | this.setColour(350); |
| | } |
| | }; |
| | Blockly.Blocks['custom_string'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('カスタム文字列:') |
| | .appendField(new Blockly.FieldTextInput(''), 'TEXT'); |
| | this.setOutput(true, 'String'); |
| | this.setColour(350); |
| | } |
| | }; |
| | Blockly.Blocks['custom_number'] = { |
| | init: function () { |
| | this.appendDummyInput() |
| | .appendField('カスタム数値:') |
| | .appendField(new Blockly.FieldTextInput(''), 'NUMBER'); |
| | this.setOutput(true, 'Number'); |
| | this.setColour(350); |
| | } |
| | }; |
| | |
| | // Blocklyワークスペースを初期化 |
| | const workspace = Blockly.inject('block-area', { |
| | toolbox: document.getElementById('toolbox'), |
| | scrollbars: true, |
| | trashcan: true, |
| | sounds: true, |
| | zoom: { |
| | controls: false, // デフォルトのズームコントロールを無効化 |
| | wheel: false, |
| | startScale: 1.0, |
| | maxScale: 2.0, |
| | minScale: 0.5, |
| | scaleSpeed: 1.2 |
| | } |
| | }); |
| | |
| | // ズームコントロールを手動で追加(インラインSVGを使用) |
| | const zoomControls = document.createElement('div'); |
| | zoomControls.className = 'blocklyZoom'; |
| | zoomControls.innerHTML = ` |
| | <svg id="zoom-in" viewBox="0 0 32 32" title="拡大"> |
| | <circle cx="16" cy="16" r="10" fill="none" stroke="#000" stroke-width="2"/> |
| | <path d="M12 16 h8 M16 12 v8" stroke="#000" stroke-width="2"/> |
| | <line x1="22" y1="22" x2="28" y2="28" stroke="#000" stroke-width="2"/> |
| | </svg> |
| | <svg id="zoom-out" viewBox="0 0 32 32" title="縮小"> |
| | <circle cx="16" cy="16" r="10" fill="none" stroke="#000" stroke-width="2"/> |
| | <path d="M12 16 h8" stroke="#000" stroke-width="2"/> |
| | <line x1="22" y1="22" x2="28" y2="28" stroke="#000" stroke-width="2"/> |
| | </svg> |
| | <svg id="zoom-reset" viewBox="0 0 32 32" title="中央寄せ"> |
| | <path d="M8 16 h16 M16 8 v16" stroke="#000" stroke-width="2"/> |
| | <path d="M8 12 l-4 4 l4 4 M24 12 l4 4 l-4 4" fill="none" stroke="#000" stroke-width="2"/> |
| | </svg> |
| | `; |
| | document.getElementById('block-area').appendChild(zoomControls); |
| | |
| | // ズームと中央寄せのイベントリスナー |
| | document.getElementById('zoom-in').addEventListener('click', function () { |
| | workspace.zoomCenter(1); // スケールを増加(ズームイン) |
| | }); |
| | |
| | document.getElementById('zoom-out').addEventListener('click', function () { |
| | workspace.zoomCenter(-1); // スケールを減少(ズームアウト) |
| | }); |
| | |
| | document.getElementById('zoom-reset').addEventListener('click', function () { |
| | const topBlocks = workspace.getTopBlocks(true); |
| | if (topBlocks.length > 0) { |
| | workspace.centerOnBlock(topBlocks[0].id); |
| | } else { |
| | workspace.scrollCenter(); |
| | } |
| | }); |
| | |
| | // コピーボタンのイベントリスナー |
| | document.getElementById('copy-button').addEventListener('click', function () { |
| | const code = document.getElementById('generated-code').textContent; |
| | navigator.clipboard.writeText(code).then(() => { |
| | const copyMessage = document.getElementById('copy-message'); |
| | copyMessage.style.display = 'block'; |
| | setTimeout(() => { |
| | copyMessage.style.display = 'none'; |
| | }, 3000); |
| | }).catch(err => { |
| | console.error('コードのコピーに失敗しました:', err); |
| | }); |
| | }); |
| | |
| | // URLからワークスペースを復元 |
| | function loadWorkspaceFromUrl() { |
| | const urlParams = new URLSearchParams(window.location.search); |
| | const compressed = urlParams.get('blocks'); |
| | if (compressed) { |
| | try { |
| | const binaryString = atob(compressed); |
| | const bytes = new Uint8Array(binaryString.length); |
| | for (let i = 0; i < binaryString.length; i++) { |
| | bytes[i] = binaryString.charCodeAt(i); |
| | } |
| | const xmlString = pako.inflate(bytes, { to: 'string' }); |
| | const xml = Blockly.utils.xml.textToDom(xmlString); |
| | workspace.clear(); |
| | Blockly.Xml.domToWorkspace(xml, workspace); |
| | } catch (e) { |
| | console.error('ワークスペースの復元に失敗しました:', e); |
| | } |
| | } |
| | } |
| | |
| | // ワークスペースをURLに保存 |
| | function saveWorkspaceToUrl() { |
| | try { |
| | const xml = Blockly.Xml.workspaceToDom(workspace); |
| | const xmlString = Blockly.Xml.domToText(xml); |
| | const compressed = pako.gzip(xmlString, { to: 'string' }); |
| | const base64 = btoa(String.fromCharCode.apply(null, compressed)); |
| | const url = new URL(window.location); |
| | url.searchParams.set('blocks', base64); |
| | history.pushState({}, '', url); |
| | } catch (e) { |
| | console.error('ワークスペースの保存に失敗しました:', e); |
| | } |
| | } |
| | |
| | // Arduinoコード生成ロジック |
| | function generateArduinoCode() { |
| | let includes = new Set(); |
| | let variables = new Set(); |
| | let servoObjects = new Set(); |
| | let servoSetup = new Set(); |
| | let lcdObjects = new Set(); |
| | let lcdSetup = new Set(); |
| | let sevenSegmentSetup = new Set(); |
| | let code = ''; |
| | const topBlocks = workspace.getTopBlocks(true); |
| | let lcdPinConfig = null; |
| | |
| | function collectDependencies(block) { |
| | if (!block) return; |
| | let currentBlock = block; |
| | while (currentBlock) { |
| | if (currentBlock.type === 'variable_declare_int' || currentBlock.type === 'variable_set_int' || currentBlock.type === 'variable_get_int') { |
| | const varField = currentBlock.getField('VAR'); |
| | if (varField && workspace.getVariableMap()) { |
| | const variable = varField.getVariable(); |
| | if (variable) { |
| | const varName = variable.name; |
| | if (varName) { |
| | variables.add(`uint8_t ${varName};`); |
| | } |
| | } |
| | } |
| | } else if (currentBlock.type === 'int_declare' || currentBlock.type === 'int_set' || currentBlock.type === 'int_get') { |
| | const varField = currentBlock.getField('VAR'); |
| | if (varField && workspace.getVariableMap()) { |
| | const variable = varField.getVariable(); |
| | if (variable) { |
| | const varName = variable.name; |
| | if (varName) { |
| | variables.add(`int ${varName};`); |
| | } |
| | } |
| | } |
| | } else if (currentBlock.type === 'float_declare' || currentBlock.type === 'float_set' || currentBlock.type === 'float_get') { |
| | const varField = currentBlock.getField('VAR'); |
| | if (varField && workspace.getVariableMap()) { |
| | const variable = varField.getVariable(); |
| | if (variable) { |
| | const varName = variable.name; |
| | if (varName) { |
| | variables.add(`float ${varName};`); |
| | } |
| | } |
| | } |
| | } else if (currentBlock.type === 'variable_set_number' || currentBlock.type === 'variable_set_string') { |
| | const varField = currentBlock.getField('VAR'); |
| | if (varField && workspace.getVariableMap()) { |
| | const variable = varField.getVariable(); |
| | if (variable) { |
| | const varName = variable.name; |
| | if (varName) { |
| | if (currentBlock.type === 'variable_set_number') { |
| | variables.add(`float ${varName};`); |
| | } else if (currentBlock.type === 'variable_set_string') { |
| | variables.add(`String ${varName};`); |
| | } |
| | } |
| | } |
| | } |
| | } else if (currentBlock.type === 'servo_write') { |
| | const pinServo = currentBlock.getFieldValue('PIN'); |
| | includes.add('#include <Servo.h>'); |
| | servoObjects.add(`Servo servo_${pinServo};`); |
| | servoSetup.add(`servo_${pinServo}.attach(${pinServo});`); |
| | } else if (currentBlock.type === 'lcd_print' || currentBlock.type === 'lcd_print_value') { |
| | includes.add('#include <LiquidCrystal.h>'); |
| | const rs = currentBlock.getFieldValue('RS'); |
| | const e = currentBlock.getFieldValue('E'); |
| | const d4 = currentBlock.getFieldValue('D4'); |
| | const d5 = currentBlock.getFieldValue('D5'); |
| | const d6 = currentBlock.getFieldValue('D6'); |
| | const d7 = currentBlock.getFieldValue('D7'); |
| | const cols = currentBlock.getFieldValue('COLS'); |
| | const rows = currentBlock.getFieldValue('ROWS'); |
| | const newPinConfig = `${rs},${e},${d4},${d5},${d6},${d7}`; |
| | if (!lcdPinConfig) { |
| | lcdPinConfig = newPinConfig; |
| | lcdObjects.add(`LiquidCrystal lcd(${rs}, ${e}, ${d4}, ${d5}, ${d6}, ${d7});`); |
| | lcdSetup.add(`lcd.begin(${cols}, ${rows});`); |
| | lcdSetup.add(`lcd.clear();`); |
| | } else if (lcdPinConfig !== newPinConfig) { |
| | console.warn(`LCDピンの設定が異なります。最初の設定(${lcdPinConfig})を使用します。`); |
| | } |
| | } else if (currentBlock.type === 'lcd_clear') { |
| | includes.add('#include <LiquidCrystal.h>'); |
| | if (!lcdPinConfig) { |
| | lcdPinConfig = '8,9,4,5,6,7'; |
| | lcdObjects.add(`LiquidCrystal lcd(8, 9, 4, 5, 6, 7);`); |
| | lcdSetup.add(`lcd.begin(16, 2);`); |
| | lcdSetup.add(`lcd.clear();`); |
| | } |
| | } else if (currentBlock.type === 'seven_segment_display') { |
| | const pinA = currentBlock.getFieldValue('PIN_A'); |
| | const pinB = currentBlock.getFieldValue('PIN_B'); |
| | const pinC = currentBlock.getFieldValue('PIN_C'); |
| | const pinD = currentBlock.getFieldValue('PIN_D'); |
| | const pinE = currentBlock.getFieldValue('PIN_E'); |
| | const pinF = currentBlock.getFieldValue('PIN_F'); |
| | const pinG = currentBlock.getFieldValue('PIN_G'); |
| | sevenSegmentSetup.add(`pinMode(${pinA}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinB}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinC}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinD}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinE}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinF}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${pinG}, OUTPUT);`); |
| | } else if (currentBlock.type === 'ultrasonic_read') { |
| | const trig = currentBlock.getFieldValue('TRIG'); |
| | const echo = currentBlock.getFieldValue('ECHO'); |
| | variables.add(`long duration_${trig};`); |
| | variables.add(`int distance_${trig};`); |
| | sevenSegmentSetup.add(`pinMode(${trig}, OUTPUT);`); |
| | sevenSegmentSetup.add(`pinMode(${echo}, INPUT);`); |
| | } else if (currentBlock.type === 'tone') { |
| | const pin = currentBlock.getFieldValue('PIN'); |
| | sevenSegmentSetup.add(`pinMode(${pin}, OUTPUT);`); |
| | } |
| | |
| | if (currentBlock.getInput('DO')) collectDependencies(currentBlock.getInputTargetBlock('DO')); |
| | if (currentBlock.getInput('DO0')) collectDependencies(currentBlock.getInputTargetBlock('DO0')); |
| | if (currentBlock.getInput('ELSE')) collectDependencies(currentBlock.getInputTargetBlock('ELSE')); |
| | if (currentBlock.getInput('SETUP_CODE')) collectDependencies(currentBlock.getInputTargetBlock('SETUP_CODE')); |
| | if (currentBlock.getInput('LOOP_CODE')) collectDependencies(currentBlock.getInputTargetBlock('LOOP_CODE')); |
| | if (currentBlock.getInput('VALUE')) collectDependencies(currentBlock.getInputTargetBlock('VALUE')); |
| | if (currentBlock.getInput('TEXT')) collectDependencies(currentBlock.getInputTargetBlock('TEXT')); |
| | if (currentBlock.getInput('NUMBER')) collectDependencies(currentBlock.getInputTargetBlock('NUMBER')); |
| | if (currentBlock.getInput('FREQUENCY')) collectDependencies(currentBlock.getInputTargetBlock('FREQUENCY')); |
| | if (currentBlock.getInput('ANGLE')) collectDependencies(currentBlock.getInputTargetBlock('ANGLE')); |
| | if (currentBlock.getInput('TIME')) collectDependencies(currentBlock.getInputTargetBlock('TIME')); |
| | if (currentBlock.getInput('A')) collectDependencies(currentBlock.getInputTargetBlock('A')); |
| | if (currentBlock.getInput('B')) collectDependencies(currentBlock.getInputTargetBlock('B')); |
| | currentBlock = currentBlock.getNextBlock(); |
| | } |
| | } |
| | |
| | topBlocks.forEach(block => collectDependencies(block)); |
| | |
| | if (includes.size > 0) { |
| | code += Array.from(includes).join('\n') + '\n\n'; |
| | } |
| | |
| | if (variables.size > 0 || servoObjects.size > 0 || lcdObjects.size > 0) { |
| | code += [...variables, ...servoObjects, ...lcdObjects].join('\n') + '\n\n'; |
| | } |
| | |
| | topBlocks.forEach(block => { |
| | if (block.type === 'setup') { |
| | code += 'void setup() {\n'; |
| | if (servoSetup.size > 0 || lcdSetup.size > 0 || sevenSegmentSetup.size > 0) { |
| | code += ` ${[...servoSetup, ...lcdSetup, ...sevenSegmentSetup].join('\n ')}\n`; |
| | } |
| | const setupCode = generateCodeForBlock(block.getInputTargetBlock('SETUP_CODE')); |
| | code += setupCode ? ` ${setupCode.replace(/\n/g, '\n ')}` : ''; |
| | code += '\n}\n\n'; |
| | } else if (block.type === 'loop') { |
| | code += 'void loop() {\n'; |
| | const loopCode = generateCodeForBlock(block.getInputTargetBlock('LOOP_CODE')); |
| | code += loopCode ? ` ${loopCode.replace(/\n/g, '\n ')}` : ''; |
| | code += '\n}\n'; |
| | } |
| | }); |
| | |
| | return code || '// コードが生成されていません'; |
| | } |
| | |
| | // Arduinoコード生成ロジック内のgenerateValueCode関数 |
| | function generateValueCode(block) { |
| | if (!block) return ''; |
| | switch (block.type) { |
| | case 'digital_read': |
| | const pinDr = block.getFieldValue('PIN'); |
| | return `digitalRead(${pinDr})`; |
| | case 'analog_read': |
| | const pinAr = block.getFieldValue('PIN'); |
| | return `analogRead(${pinAr})`; |
| | case 'serial_read_number': |
| | return `Serial.parseInt()`; |
| | case 'serial_read_string': |
| | return `Serial.readString()`; // クリーンアップせず、そのまま返す |
| | case 'logic_compare': |
| | const aComp = generateValueCode(block.getInputTargetBlock('A')) || '0'; |
| | const opComp = block.getFieldValue('OP'); |
| | const bComp = generateValueCode(block.getInputTargetBlock('B')) || '0'; |
| | const operators = { 'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>=' }; |
| | return `(${aComp} ${operators[opComp]} ${bComp})`; |
| | case 'string_compare': |
| | let aStr = generateValueCode(block.getInputTargetBlock('A')) || '""'; |
| | let bStr = generateValueCode(block.getInputTargetBlock('B')) || '""'; |
| | const opStr = block.getFieldValue('OP'); |
| | // Serial.readString()の場合、クリーンアップしない |
| | if (block.getInputTargetBlock('A')?.type !== 'serial_read_string') { |
| | aStr = cleanString(aStr); |
| | } |
| | if (block.getInputTargetBlock('B')?.type !== 'serial_read_string') { |
| | bStr = cleanString(bStr); |
| | } |
| | if (opStr === 'EQ') { |
| | return `(${aStr} == ${bStr})`; |
| | } else { // NEQ |
| | return `(${aStr} != ${bStr})`; |
| | } |
| | case 'logic_operation': |
| | const aLogic = generateValueCode(block.getInputTargetBlock('A')) || 'true'; |
| | const opLogic = block.getFieldValue('OP'); |
| | const bLogic = generateValueCode(block.getInputTargetBlock('B')) || 'true'; |
| | const logicOps = { 'AND': '&&', 'OR': '||' }; |
| | return `(${aLogic} ${logicOps[opLogic]} ${bLogic})`; |
| | case 'math_arithmetic': |
| | const aMath = generateValueCode(block.getInputTargetBlock('A')) || '0'; |
| | const opMath = block.getFieldValue('OP'); |
| | const bMath = generateValueCode(block.getInputTargetBlock('B')) || '0'; |
| | const mathOps = { 'ADD': '+', 'MINUS': '-', 'MULTIPLY': '*', 'DIVIDE': '/' }; |
| | return `(${aMath} ${mathOps[opMath]} ${bMath})`; |
| | case 'math_single': |
| | const numSingle = generateValueCode(block.getInputTargetBlock('NUM')) || '0'; |
| | const opSingle = block.getFieldValue('OP'); |
| | return `${opSingle.toLowerCase()}(${numSingle})`; |
| | case 'math_trig': |
| | const numTrig = generateValueCode(block.getInputTargetBlock('NUM')) || '0'; |
| | const opTrig = block.getFieldValue('OP'); |
| | return `${opTrig.toLowerCase()}(${numTrig})`; |
| | case 'random_number': |
| | const min = generateValueCode(block.getInputTargetBlock('MIN')) || '0'; |
| | const max = generateValueCode(block.getInputTargetBlock('MAX')) || '100'; |
| | return `random(${min}, ${max})`; |
| | case 'divide': |
| | const num = generateValueCode(block.getInputTargetBlock('NUM')) || '10'; |
| | const div = generateValueCode(block.getInputTargetBlock('DIV')) || '2'; |
| | return `(${num} / ${div})`; |
| | case 'number_input': |
| | const numberValue = block.getFieldValue('VALUE'); |
| | return `${numberValue}`; |
| | case 'string_input': |
| | const stringValue = block.getFieldValue('TEXT'); |
| | return `"${stringValue.replace(/"/g, '\\"')}"`; // 通常の文字列はクリーンアップ |
| | case 'text_input': |
| | const textValue = block.getFieldValue('TEXT'); |
| | return `"${textValue.replace(/"/g, '\\"')}"`; // 通常の文字列はクリーンアップ |
| | case 'custom_string': |
| | const customStringValue = block.getFieldValue('TEXT'); |
| | return `"${customStringValue.replace(/"/g, '\\"')}"`; |
| | case 'custom_number': |
| | const customNumberValue = block.getFieldValue('NUMBER'); |
| | return `${customNumberValue}`; // そのまま数値として扱う |
| | case 'variable_get_int': |
| | const varField = block.getField('VAR'); |
| | return varField && varField.getVariable() ? varField.getVariable().name : 'unknown_var'; |
| | case 'int_get': |
| | const varFieldIntGet = block.getField('VAR'); |
| | return varFieldIntGet && varFieldIntGet.getVariable() ? varFieldIntGet.getVariable().name : 'unknown_var'; |
| | case 'float_get': |
| | const varFieldFloatGet = block.getField('VAR'); |
| | return varFieldFloatGet && varFieldFloatGet.getVariable() ? varFieldFloatGet.getVariable().name : 'unknown_var'; |
| | case 'ultrasonic_distance': |
| | const trig = block.getFieldValue('TRIG'); |
| | return `distance_${trig}`; |
| | default: |
| | return ''; |
| | } |
| | } |
| | |
| | function generateCodeForBlock(block) { |
| | if (!block) return ''; |
| | let code = ''; |
| | while (block) { |
| | switch (block.type) { |
| | case 'pin_mode': |
| | const pin = block.getFieldValue('PIN'); |
| | const mode = block.getFieldValue('MODE'); |
| | code += `pinMode(${pin}, ${mode});\n`; |
| | break; |
| | case 'digital_write': |
| | const pinDw = block.getFieldValue('PIN'); |
| | const value = block.getFieldValue('VALUE'); |
| | code += `digitalWrite(${pinDw}, ${value});\n`; |
| | break; |
| | case 'analog_write': |
| | const pinAw = block.getFieldValue('PIN'); |
| | const valueAw = generateValueCode(block.getInputTargetBlock('VALUE')) || '255'; |
| | code += `analogWrite(${pinAw}, ${valueAw});\n`; |
| | break; |
| | case 'delay': |
| | const time = block.getFieldValue('TIME'); |
| | code += `delay(${time});\n`; |
| | break; |
| | case 'delay_microseconds': |
| | const timeUs = block.getFieldValue('TIME'); |
| | code += `delayMicroseconds(${timeUs});\n`; |
| | break; |
| | case 'delay_microseconds_value': |
| | const timeUsValue = generateValueCode(block.getInputTargetBlock('TIME')) || '100'; |
| | code += `delayMicroseconds(${timeUsValue});\n`; |
| | break; |
| | case 'delay_value': |
| | const timeValue = generateValueCode(block.getInputTargetBlock('TIME')) || '1000'; |
| | code += `delay(${timeValue});\n`; |
| | break; |
| | case 'controls_while': |
| | const conditionW = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'true'; |
| | const doCodeW = generateCodeForBlock(block.getInputTargetBlock('DO')); |
| | code += `while (${conditionW}) {\n ${doCodeW.replace(/\n/g, '\n ')}\n}\n`; |
| | break; |
| | case 'controls_if': |
| | const conditionIf = generateValueCode(block.getInputTargetBlock('IF0')) || 'true'; |
| | const doCodeIf = generateCodeForBlock(block.getInputTargetBlock('DO0')); |
| | const elseCode = generateCodeForBlock(block.getInputTargetBlock('ELSE')); |
| | code += `if (${conditionIf}) {\n ${doCodeIf.replace(/\n/g, '\n ')}\n}`; |
| | if (elseCode) code += ` else {\n ${elseCode.replace(/\n/g, '\n ')}\n}`; |
| | code += '\n'; |
| | break; |
| | case 'repeat_times': |
| | const times = generateValueCode(block.getInputTargetBlock('TIMES')) || '5'; |
| | const doCode = generateCodeForBlock(block.getInputTargetBlock('DO')); |
| | code += `for (int i = 0; i < ${times}; i++) {\n ${doCode.replace(/\n/g, '\n ')}\n}\n`; |
| | break; |
| | case 'if_condition': |
| | const condition = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'true'; |
| | const ifCode = generateCodeForBlock(block.getInputTargetBlock('DO')); |
| | code += `if (${condition}) {\n ${ifCode.replace(/\n/g, '\n ')}\n}\n`; |
| | break; |
| | case 'wait_until_condition': |
| | const waitCondition = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'false'; |
| | code += `while (!${waitCondition}) {\n delay(10);\n}\n`; |
| | break; |
| | case 'variable_declare_int': |
| | break; |
| | case 'variable_set_int': |
| | const varField = block.getField('VAR'); |
| | const varName = varField && varField.getVariable() ? varField.getVariable().name : 'unknown_var'; |
| | const valueIntNew = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `${varName} = ${valueIntNew};\n`; |
| | break; |
| | case 'int_declare': |
| | break; |
| | case 'int_set': |
| | const varFieldInt = block.getField('VAR'); |
| | const varNameInt = varFieldInt && varFieldInt.getVariable() ? varFieldInt.getVariable().name : 'unknown_var'; |
| | const valueInt = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `${varNameInt} = ${valueInt};\n`; |
| | break; |
| | case 'float_declare': |
| | break; |
| | case 'float_set': |
| | const varFieldFloat = block.getField('VAR'); |
| | const varNameFloat = varFieldFloat && varFieldFloat.getVariable() ? varFieldFloat.getVariable().name : 'unknown_var'; |
| | const valueFloat = generateValueCode(block.getInputTargetBlock('VALUE')) || '0.0'; |
| | code += `${varNameFloat} = ${valueFloat};\n`; |
| | break; |
| | case 'variable_set_number': |
| | const varFieldNum = block.getField('VAR'); |
| | const varNameNum = varFieldNum && varFieldNum.getVariable() ? varFieldNum.getVariable().name : 'unknown_var'; |
| | const valueNum = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `${varNameNum} = ${valueNum};\n`; |
| | break; |
| | case 'variable_set_string': |
| | const varFieldStr = block.getField('VAR'); |
| | const varNameStr = varFieldStr && varFieldStr.getVariable() ? varFieldStr.getVariable().name : 'unknown_var'; |
| | let valueStr = generateValueCode(block.getInputTargetBlock('TEXT')) || '""'; |
| | if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') { |
| | valueStr = cleanString(valueStr); |
| | } |
| | code += `${varNameStr} = ${valueStr};\n`; |
| | break; |
| | case 'servo_write': |
| | const pinServo = block.getFieldValue('PIN'); |
| | const angle = generateValueCode(block.getInputTargetBlock('ANGLE')) || '90'; |
| | code += `servo_${pinServo}.write(${angle});\n`; |
| | break; |
| | case 'ultrasonic_read': |
| | const trig = block.getFieldValue('TRIG'); |
| | const echo = block.getFieldValue('ECHO'); |
| | code += `digitalWrite(${trig}, LOW);\n`; |
| | code += `delayMicroseconds(2);\n`; |
| | code += `digitalWrite(${trig}, HIGH);\n`; |
| | code += `delayMicroseconds(10);\n`; |
| | code += `digitalWrite(${trig}, LOW);\n`; |
| | code += `duration_${trig} = pulseIn(${echo}, HIGH);\n`; |
| | code += `distance_${trig} = duration_${trig} * 0.034 / 2;\n`; |
| | break; |
| | case 'lcd_print': |
| | const cursorCol = block.getFieldValue('CURSOR_COL'); |
| | const cursorRow = block.getFieldValue('CURSOR_ROW'); |
| | let textLcd = generateValueCode(block.getInputTargetBlock('TEXT')) || '"Hello World!!"'; |
| | if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') { |
| | textLcd = cleanString(textLcd); |
| | } |
| | code += `lcd.setCursor(${cursorCol}, ${cursorRow});\nlcd.print(${textLcd});\n`; |
| | break; |
| | case 'lcd_print_value': |
| | const cursorColVal = block.getFieldValue('CURSOR_COL'); |
| | const cursorRowVal = block.getFieldValue('CURSOR_ROW'); |
| | const valueLcd = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `lcd.setCursor(${cursorColVal}, ${cursorRowVal});\nlcd.print(${valueLcd});\n`; |
| | break; |
| | case 'lcd_clear': |
| | code += `lcd.clear();\n`; |
| | break; |
| | case 'serial_begin': |
| | const baud = block.getFieldValue('BAUD'); |
| | code += `Serial.begin(${baud});\n`; |
| | break; |
| | case 'serial_print': |
| | let textSerial = generateValueCode(block.getInputTargetBlock('TEXT')) || '""'; |
| | if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') { |
| | textSerial = cleanString(textSerial); |
| | } |
| | code += `Serial.print(${textSerial});\n`; |
| | break; |
| | case 'serial_print_value': |
| | const valueSerial = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `Serial.print(${valueSerial});\n`; |
| | break; |
| | case 'serial_println': |
| | let textSerialLn = generateValueCode(block.getInputTargetBlock('TEXT')) || '""'; |
| | if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') { |
| | textSerialLn = cleanString(textSerialLn); |
| | } |
| | code += `Serial.println(${textSerialLn});\n`; |
| | break; |
| | case 'serial_println_value': |
| | const valueSerialLn = generateValueCode(block.getInputTargetBlock('VALUE')) || '0'; |
| | code += `Serial.println(${valueSerialLn});\n`; |
| | break; |
| | case 'custom_code': |
| | const customCode = block.getFieldValue('CODE'); |
| | code += `${customCode}\n`; |
| | break; |
| | case 'seven_segment_display': |
| | const pinA = block.getFieldValue('PIN_A'); |
| | const pinB = block.getFieldValue('PIN_B'); |
| | const pinC = block.getFieldValue('PIN_C'); |
| | const pinD = block.getFieldValue('PIN_D'); |
| | const pinE = block.getFieldValue('PIN_E'); |
| | const pinF = block.getFieldValue('PIN_F'); |
| | const pinG = block.getFieldValue('PIN_G'); |
| | const number = generateValueCode(block.getInputTargetBlock('NUMBER')) || '0'; |
| | code += `if (${number} == -1) {\n`; |
| | code += ` digitalWrite(${pinA}, LOW);\n`; |
| | code += ` digitalWrite(${pinB}, LOW);\n`; |
| | code += ` digitalWrite(${pinC}, LOW);\n`; |
| | code += ` digitalWrite(${pinD}, LOW);\n`; |
| | code += ` digitalWrite(${pinE}, LOW);\n`; |
| | code += ` digitalWrite(${pinF}, LOW);\n`; |
| | code += ` digitalWrite(${pinG}, LOW);\n`; |
| | code += `} else {\n`; |
| | code += ` int digit = constrain(${number}, 0, 9);\n`; |
| | code += ` digitalWrite(${pinA}, ${segmentPatterns[0][0] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinB}, ${segmentPatterns[0][1] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinC}, ${segmentPatterns[0][2] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinD}, ${segmentPatterns[0][3] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinE}, ${segmentPatterns[0][4] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinF}, ${segmentPatterns[0][5] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` digitalWrite(${pinG}, ${segmentPatterns[0][6] ? 'HIGH' : 'LOW'});\n`; |
| | code += ` if (digit == 1) { digitalWrite(${pinA}, ${segmentPatterns[1][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[1][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[1][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[1][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[1][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[1][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[1][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 2) { digitalWrite(${pinA}, ${segmentPatterns[2][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[2][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[2][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[2][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[2][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[2][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[2][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 3) { digitalWrite(${pinA}, ${segmentPatterns[3][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[3][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[3][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[3][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[3][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[3][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[3][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 4) { digitalWrite(${pinA}, ${segmentPatterns[4][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[4][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[4][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[4][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[4][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[4][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[4][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 5) { digitalWrite(${pinA}, ${segmentPatterns[5][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[5][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[5][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[5][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[5][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[5][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[5][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 6) { digitalWrite(${pinA}, ${segmentPatterns[6][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[6][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[6][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[6][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[6][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[6][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[6][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 7) { digitalWrite(${pinA}, ${segmentPatterns[7][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[7][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[7][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[7][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[7][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[7][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[7][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 8) { digitalWrite(${pinA}, ${segmentPatterns[8][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[8][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[8][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[8][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[8][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[8][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[8][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += ` else if (digit == 9) { digitalWrite(${pinA}, ${segmentPatterns[9][0] ? 'HIGH' : 'LOW'}); digitalWrite(${pinB}, ${segmentPatterns[9][1] ? 'HIGH' : 'LOW'}); digitalWrite(${pinC}, ${segmentPatterns[9][2] ? 'HIGH' : 'LOW'}); digitalWrite(${pinD}, ${segmentPatterns[9][3] ? 'HIGH' : 'LOW'}); digitalWrite(${pinE}, ${segmentPatterns[9][4] ? 'HIGH' : 'LOW'}); digitalWrite(${pinF}, ${segmentPatterns[9][5] ? 'HIGH' : 'LOW'}); digitalWrite(${pinG}, ${segmentPatterns[9][6] ? 'HIGH' : 'LOW'}); }\n`; |
| | code += `}\n`; |
| | break; |
| | case 'tone': |
| | const tonePin = block.getFieldValue('PIN'); |
| | const frequency = generateValueCode(block.getInputTargetBlock('FREQUENCY')) || '440'; |
| | code += `tone(${tonePin}, ${frequency});\n`; |
| | break; |
| | case 'noTone': |
| | const noTonePin = block.getFieldValue('PIN'); |
| | code += `noTone(${noTonePin});\n`; |
| | break; |
| | } |
| | block = block.getNextBlock(); |
| | } |
| | return code; |
| | } |
| | |
| | workspace.addChangeListener(function (event) { |
| | const arduinoCode = generateArduinoCode(); |
| | document.getElementById('generated-code').textContent = arduinoCode; |
| | if (event.type === Blockly.Events.BLOCK_CREATE || |
| | event.type === Blockly.Events.BLOCK_DELETE || |
| | event.type === Blockly.Events.BLOCK_MOVE || |
| | event.type === Blockly.Events.BLOCK_CHANGE) { |
| | saveWorkspaceToUrl(); |
| | } |
| | }); |
| | |
| | document.getElementById('clear-btn').addEventListener('click', function () { |
| | workspace.clear(); |
| | document.getElementById('generated-code').textContent = '// 生成されたArduinoコードがここに表示されます'; |
| | const url = new URL(window.location); |
| | url.searchParams.delete('blocks'); |
| | history.pushState({}, '', url); |
| | }); |
| | |
| | document.getElementById('save-btn').addEventListener('click', function () { |
| | const url = window.location.href; |
| | navigator.clipboard.writeText(url).then(() => { |
| | alert('URLがクリップボードにコピーされました!'); |
| | }).catch(err => { |
| | console.error('URLのコピーに失敗しました:', err); |
| | }); |
| | }); |
| | |
| | document.getElementById('download-btn').addEventListener('click', function () { |
| | const code = document.getElementById('generated-code').textContent; |
| | const now = new Date(); |
| | const timestamp = now.getFullYear() + |
| | ('0' + (now.getMonth() + 1)).slice(-2) + |
| | ('0' + now.getDate()).slice(-2) + |
| | ('0' + now.getHours()).slice(-2) + |
| | ('0' + now.getMinutes()).slice(-2); |
| | const filename = `${timestamp}.ino`; |
| | const blob = new Blob([code], { type: 'text/x-arduino' }); |
| | const url = window.URL.createObjectURL(blob); |
| | const a = document.createElement('a'); |
| | a.href = url; |
| | a.download = filename; |
| | document.body.appendChild(a); |
| | a.click(); |
| | document.body.removeChild(a); |
| | window.URL.revokeObjectURL(url); |
| | }); |
| | |
| | document.getElementById('print-btn').addEventListener('click', function () { |
| | html2canvas(document.getElementById('block-area')).then(canvas => { |
| | const image = canvas.toDataURL('image/png'); |
| | const printWindow = window.open(''); |
| | printWindow.document.write('<img src="' + image + '" onload="window.print();window.close()" />'); |
| | printWindow.document.close(); |
| | }); |
| | }); |
| | |
| | // シリアル通信ボタンのイベントリスナー |
| | document.getElementById('serial-btn').addEventListener('click', function () { |
| | const modal = document.getElementById('serial-modal'); |
| | const iframe = document.getElementById('serial-iframe'); |
| | iframe.src = 'pv17-3.html'; // index2.htmlを読み込む |
| | modal.style.display = 'block'; // モーダルを表示 |
| | }); |
| | |
| | // 閉じるボタンのイベントリスナー |
| | document.getElementById('close-modal').addEventListener('click', function () { |
| | const modal = document.getElementById('serial-modal'); |
| | const iframe = document.getElementById('serial-iframe'); |
| | modal.style.display = 'none'; // モーダルを非表示 |
| | iframe.src = ''; // iframeの内容をリセット |
| | }); |
| | |
| | document.getElementById('exit-btn').addEventListener('click', function () { |
| | window.location.href = 'https://huggingface.co/ek15072809'; |
| | }); |
| | |
| | loadWorkspaceFromUrl(); |
| | </script> |
| | </body> |
| | </html> |