ek15072809 commited on
Commit
834aa44
·
verified ·
1 Parent(s): c4eef52

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1809 -19
index.html CHANGED
@@ -1,19 +1,1809 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- Copyright (C) 2025 Yuna Hamaoka, Yuito Takasaki -->
2
+ <!DOCTYPE html>
3
+ <html lang="ja">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Arduinoビジュアルプログラミング</title>
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ margin: 0;
12
+ padding: 20px;
13
+ background-color: #f0f0f0;
14
+ }
15
+
16
+ .container {
17
+ display: flex;
18
+ gap: 20px;
19
+ max-width: 1200px;
20
+ margin: 0 auto;
21
+ align-items: stretch;
22
+ }
23
+
24
+ #block-area {
25
+ width: 60%;
26
+ height: 600px;
27
+ background-color: #fff;
28
+ border: 2px solid #ccc;
29
+ border-radius: 5px;
30
+ position: relative;
31
+ }
32
+
33
+ #code-area {
34
+ width: 40%;
35
+ height: 600px;
36
+ background-color: #333;
37
+ color: #fff;
38
+ border-radius: 5px;
39
+ padding: 10px;
40
+ overflow-y: auto;
41
+ font-family: monospace;
42
+ box-sizing: border-box;
43
+ position: relative;
44
+ }
45
+
46
+ #copy-button {
47
+ position: absolute;
48
+ top: 10px;
49
+ right: 10px;
50
+ cursor: pointer;
51
+ }
52
+
53
+ #copy-message {
54
+ position: absolute;
55
+ top: 40px;
56
+ right: 10px;
57
+ background-color: rgba(0, 0, 0, 0.7);
58
+ color: #fff;
59
+ padding: 5px 10px;
60
+ border-radius: 3px;
61
+ font-size: 12px;
62
+ display: none;
63
+ }
64
+
65
+ .highlight {
66
+ background-color: #FFFF99 !important;
67
+ color: #000 !important;
68
+ }
69
+
70
+ .button-container {
71
+ max-width: 1200px;
72
+ margin: 20px auto 0;
73
+ display: flex;
74
+ justify-content: space-between;
75
+ align-items: center;
76
+ }
77
+
78
+ .left-buttons {
79
+ display: flex;
80
+ gap: 10px;
81
+ }
82
+
83
+ .right-buttons {
84
+ display: flex;
85
+ gap: 10px;
86
+ }
87
+
88
+ button {
89
+ padding: 10px 20px;
90
+ font-size: 16px;
91
+ border: none;
92
+ border-radius: 5px;
93
+ cursor: pointer;
94
+ }
95
+
96
+ #save-btn {
97
+ background-color: #28a745;
98
+ color: white;
99
+ }
100
+
101
+ #save-btn:hover {
102
+ background-color: #218838;
103
+ }
104
+
105
+ #clear-btn {
106
+ background-color: #dc3545;
107
+ color: white;
108
+ }
109
+
110
+ #clear-btn:hover {
111
+ background-color: #b02a37;
112
+ }
113
+
114
+ #download-btn {
115
+ background-color: #007bff;
116
+ color: white;
117
+ }
118
+
119
+ #download-btn:hover {
120
+ background-color: #0056b3;
121
+ }
122
+
123
+ #print-btn {
124
+ background-color: #ffc107;
125
+ color: black;
126
+ }
127
+
128
+ #print-btn:hover {
129
+ background-color: #e0a800;
130
+ }
131
+
132
+ #exit-btn {
133
+ background-color: #6c757d;
134
+ color: white;
135
+ }
136
+
137
+ #exit-btn:hover {
138
+ background-color: #5a6268;
139
+ }
140
+
141
+ /* Blocklyズームコントロールのスタイル */
142
+ .blocklyZoom {
143
+ position: absolute;
144
+ bottom: 100px; /* ゴミ箱アイコンの上に配置 */
145
+ right: 43px;
146
+ display: flex;
147
+ flex-direction: column;
148
+ gap: 2px;
149
+ z-index: 10; /* ゴミ箱より手前に */
150
+ }
151
+
152
+ .blocklyZoom svg {
153
+ width: 32px;
154
+ height: 32px;
155
+ cursor: pointer;
156
+ }
157
+
158
+ /* ゴミ箱アイコンの位置調整 */
159
+ .blocklyTrash {
160
+ bottom: 10px !important;
161
+ right: 10px !important;
162
+ }
163
+
164
+ #serial-btn {
165
+ background-color: #17a2b8;
166
+ color: white;
167
+ }
168
+
169
+ #serial-btn:hover {
170
+ background-color: #138496;
171
+ }
172
+ </style>
173
+ </head>
174
+ <body>
175
+ <div class="container">
176
+ <div id="block-area"></div>
177
+ <div id="code-area">
178
+ <img id="copy-button" src="copy.png" alt="Copy Code" title="コードをコピー">
179
+ <div id="copy-message">クリップボードにコピーしました</div>
180
+ <pre id="generated-code">// 生成されたArduinoコードがここに表示されます</pre>
181
+ </div>
182
+ </div>
183
+ <div class="button-container">
184
+ <div class="left-buttons">
185
+ <button id="save-btn">保存</button>
186
+ <button id="download-btn">ダウンロード</button>
187
+ <button id="print-btn">印刷</button>
188
+ <button id="serial-btn">シリアル通信</button> <!-- 追加 -->
189
+ <button id="clear-btn">クリア</button>
190
+ </div>
191
+ <div class="right-buttons">
192
+ <button id="exit-btn">終了</button>
193
+ </div>
194
+ </div>
195
+
196
+ <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;">
197
+ <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 875px; height: 644px; background: #fff; border-radius: 5px; overflow: hidden;">
198
+ <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>
199
+ <iframe id="serial-iframe" src="" style="width: 100%; height: calc(100% - 50px); margin-top: 50px; border: none;"></iframe>
200
+ </div>
201
+ </div>
202
+
203
+ <!-- ツールボックスの定義(カテゴリ付き) -->
204
+ <xml id="toolbox" style="display: none">
205
+ <category name="制御" colour="120">
206
+ <block type="setup"></block>
207
+ <block type="loop"></block>
208
+ <block type="delay">
209
+ <value name="TIME">
210
+ <shadow type="math_number">
211
+ <field name="NUM">1000</field>
212
+ </shadow>
213
+ </value>
214
+ </block>
215
+ <block type="delay_value">
216
+ <value name="TIME">
217
+ <shadow type="math_number">
218
+ <field name="NUM">1000</field>
219
+ </shadow>
220
+ </value>
221
+ </block>
222
+ <block type="delay_microseconds">
223
+ <value name="TIME">
224
+ <shadow type="math_number">
225
+ <field name="NUM">100</field>
226
+ </shadow>
227
+ </value>
228
+ </block>
229
+ <block type="delay_microseconds_value">
230
+ <value name="TIME">
231
+ <shadow type="math_number">
232
+ <field name="NUM">100</field>
233
+ </shadow>
234
+ </value>
235
+ </block>
236
+ <block type="controls_while"></block>
237
+ <block type="controls_if"></block>
238
+ <block type="repeat_times">
239
+ <value name="TIMES">
240
+ <shadow type="math_number">
241
+ <field name="NUM">5</field>
242
+ </shadow>
243
+ </value>
244
+ </block>
245
+ <block type="if_condition"></block>
246
+ <block type="wait_until_condition"></block>
247
+ </category>
248
+ <category name="ピン" colour="160">
249
+ <block type="pin_mode">
250
+ <value name="PIN">
251
+ <shadow type="math_number">
252
+ <field name="NUM">13</field>
253
+ </shadow>
254
+ </value>
255
+ </block>
256
+ <block type="digital_write">
257
+ <value name="PIN">
258
+ <shadow type="math_number">
259
+ <field name="NUM">13</field>
260
+ </shadow>
261
+ </value>
262
+ </block>
263
+ <block type="digital_read">
264
+ <value name="PIN">
265
+ <shadow type="math_number">
266
+ <field name="NUM">13</field>
267
+ </shadow>
268
+ </value>
269
+ </block>
270
+ <block type="analog_read"></block>
271
+ <block type="analog_write">
272
+ <value name="PIN">
273
+ <shadow type="math_number">
274
+ <field name="NUM">9</field>
275
+ </shadow>
276
+ </value>
277
+ <value name="VALUE">
278
+ <shadow type="math_number">
279
+ <field name="NUM">255</field>
280
+ </shadow>
281
+ </value>
282
+ </block>
283
+ </category>
284
+ <category name="テスト" colour="210">
285
+ <block type="logic_compare"></block>
286
+ <block type="logic_operation"></block>
287
+ <block type="string_compare">
288
+ <value name="A">
289
+ <shadow type="text">
290
+ <field name="TEXT">text1</field>
291
+ </shadow>
292
+ </value>
293
+ <value name="B">
294
+ <shadow type="text">
295
+ <field name="TEXT">text2</field>
296
+ </shadow>
297
+ </value>
298
+ </block>
299
+ </category>
300
+ <category name="計算" colour="230">
301
+ <block type="math_arithmetic"></block>
302
+ <block type="math_single"></block>
303
+ <block type="math_trig"></block>
304
+ <block type="random_number">
305
+ <value name="MIN">
306
+ <shadow type="math_number">
307
+ <field name="NUM">0</field>
308
+ </shadow>
309
+ </value>
310
+ <value name="MAX">
311
+ <shadow type="math_number">
312
+ <field name="NUM">100</field>
313
+ </shadow>
314
+ </value>
315
+ </block>
316
+ <block type="divide">
317
+ <value name="NUM">
318
+ <shadow type="math_number">
319
+ <field name="NUM">10</field>
320
+ </shadow>
321
+ </value>
322
+ <value name="DIV">
323
+ <shadow type="math_number">
324
+ <field name="NUM">2</field>
325
+ </shadow>
326
+ </value>
327
+ </block>
328
+ <block type="number_input">
329
+ <field name="VALUE">0</field>
330
+ </block>
331
+ <block type="string_input">
332
+ <field name="TEXT">Hello</field>
333
+ </block>
334
+ <block type="text_input">
335
+ <field name="TEXT">Hello</field>
336
+ </block>
337
+ </category>
338
+ <category name="変数" colour="260">
339
+ <block type="variable_declare_int"></block>
340
+ <block type="variable_set_int"></block>
341
+ <block type="variable_get_int"></block>
342
+ <block type="int_declare"></block>
343
+ <block type="int_set"></block>
344
+ <block type="int_get"></block>
345
+ <block type="float_declare"></block>
346
+ <block type="float_set"></block>
347
+ <block type="float_get"></block>
348
+ </category>
349
+ <category name="Generic Hardware" colour="290">
350
+ <block type="servo_write">
351
+ <value name="PIN">
352
+ <shadow type="math_number">
353
+ <field name="NUM">9</field>
354
+ </shadow>
355
+ </value>
356
+ <value name="ANGLE">
357
+ <shadow type="math_number">
358
+ <field name="NUM">90</field>
359
+ </shadow>
360
+ </value>
361
+ </block>
362
+ <block type="ultrasonic_read"></block>
363
+ <block type="ultrasonic_distance"></block>
364
+ <block type="lcd_print">
365
+ <value name="TEXT">
366
+ <shadow type="text">
367
+ <field name="TEXT">Hello World!!</field>
368
+ </shadow>
369
+ </value>
370
+ </block>
371
+ <block type="lcd_print_value">
372
+ <value name="VALUE">
373
+ <shadow type="math_number">
374
+ <field name="NUM">0</field>
375
+ </shadow>
376
+ </value>
377
+ </block>
378
+ <block type="lcd_clear"></block>
379
+ <block type="seven_segment_display">
380
+ <value name="NUMBER">
381
+ <shadow type="math_number">
382
+ <field name="NUM">0</field>
383
+ </shadow>
384
+ </value>
385
+ </block>
386
+ <block type="tone">
387
+ <value name="FREQUENCY">
388
+ <shadow type="math_number">
389
+ <field name="NUM">440</field>
390
+ </shadow>
391
+ </value>
392
+ </block>
393
+ <block type="noTone"></block>
394
+ </category>
395
+ <category name="通信" colour="320">
396
+ <block type="serial_begin"></block>
397
+ <block type="serial_print">
398
+ <value name="TEXT">
399
+ <shadow type="text">
400
+ <field name="TEXT">Hello</field>
401
+ </shadow>
402
+ </value>
403
+ </block>
404
+ <block type="serial_print_value">
405
+ <value name="VALUE">
406
+ <shadow type="math_number">
407
+ <field name="NUM">0</field>
408
+ </shadow>
409
+ </value>
410
+ </block>
411
+ <block type="serial_println">
412
+ <value name="TEXT">
413
+ <shadow type="text">
414
+ <field name="TEXT">Hello</field>
415
+ </shadow>
416
+ </value>
417
+ </block>
418
+ <block type="serial_println_value">
419
+ <value name="VALUE">
420
+ <shadow type="math_number">
421
+ <field name="NUM">0</field>
422
+ </shadow>
423
+ </value>
424
+ </block>
425
+ <block type="serial_read_number"></block>
426
+ <block type="serial_read_string"></block>
427
+ </category>
428
+ <category name="拡張" colour="350">
429
+ <block type="custom_code"></block>
430
+ <block type="custom_string"></block>
431
+ <block type="custom_number"></block>
432
+ </category>
433
+ </xml>
434
+
435
+ <!-- BlocklyをCDNから読み込み -->
436
+ <script src="./blockly.min.js"></script>
437
+ <!-- 日本語対応 -->
438
+ <script src="./ja.js"></script>
439
+ <!-- pakoライブラリを読み込み(圧縮用) -->
440
+ <script src="./pako.min.js"></script>
441
+ <!-- html2canvasライブラリを読み込み(画像保存用) -->
442
+ <script src="html2canvas.min.js"></script>
443
+
444
+ <script>
445
+ // 文字列をクリーンアップする関数
446
+ function cleanString(str) {
447
+ if (!str) return '""';
448
+ let cleaned = str.replace(/^\s*\(?['"]?(.*?)['"]?\)?\s*$/, '$1');
449
+ if (cleaned === '') return '""';
450
+ if (!cleaned.startsWith('"') || !cleaned.endsWith('"')) {
451
+ cleaned = `"${cleaned.replace(/"/g, '\\"')}"`;
452
+ }
453
+ return cleaned;
454
+ }
455
+
456
+ // 7セグメントLEDの数字マッピング(カソードコモン、HIGH=点灯)
457
+ const segmentPatterns = [
458
+ [1, 1, 1, 1, 1, 1, 0], // 0
459
+ [0, 1, 1, 0, 0, 0, 0], // 1
460
+ [1, 1, 0, 1, 1, 0, 1], // 2
461
+ [1, 1, 1, 1, 0, 0, 1], // 3
462
+ [0, 1, 1, 0, 0, 1, 1], // 4
463
+ [1, 0, 1, 1, 0, 1, 1], // 5
464
+ [1, 0, 1, 1, 1, 1, 1], // 6
465
+ [1, 1, 1, 0, 0, 0, 0], // 7
466
+ [1, 1, 1, 1, 1, 1, 1], // 8
467
+ [1, 1, 1, 1, 0, 1, 1] // 9
468
+ ];
469
+
470
+ // カスタムブロックの定義
471
+ // 制御
472
+ Blockly.Blocks['setup'] = {
473
+ init: function () {
474
+ this.appendStatementInput('SETUP_CODE').appendField('セットアップ');
475
+ this.setColour(120);
476
+ }
477
+ };
478
+ Blockly.Blocks['loop'] = {
479
+ init: function () {
480
+ this.appendStatementInput('LOOP_CODE').appendField('ループ');
481
+ this.setColour(120);
482
+ }
483
+ };
484
+ Blockly.Blocks['delay'] = {
485
+ init: function () {
486
+ this.appendDummyInput()
487
+ .appendField('待機:')
488
+ .appendField(new Blockly.FieldNumber(1000, 0), 'TIME')
489
+ .appendField('ms');
490
+ this.setPreviousStatement(true);
491
+ this.setNextStatement(true);
492
+ this.setColour(120);
493
+ }
494
+ };
495
+ Blockly.Blocks['delay_value'] = {
496
+ init: function () {
497
+ this.appendValueInput('TIME')
498
+ .setCheck('Number')
499
+ .appendField('待機:');
500
+ this.appendDummyInput()
501
+ .appendField('ms');
502
+ this.setPreviousStatement(true);
503
+ this.setNextStatement(true);
504
+ this.setColour(120);
505
+ }
506
+ };
507
+ Blockly.Blocks['delay_microseconds'] = {
508
+ init: function () {
509
+ this.appendDummyInput()
510
+ .appendField('待機:')
511
+ .appendField(new Blockly.FieldNumber(100, 0), 'TIME')
512
+ .appendField('μs');
513
+ this.setPreviousStatement(true);
514
+ this.setNextStatement(true);
515
+ this.setColour(120);
516
+ }
517
+ };
518
+ Blockly.Blocks['delay_microseconds_value'] = {
519
+ init: function () {
520
+ this.appendValueInput('TIME')
521
+ .setCheck('Number')
522
+ .appendField('待機:');
523
+ this.appendDummyInput()
524
+ .appendField('μs');
525
+ this.setPreviousStatement(true);
526
+ this.setNextStatement(true);
527
+ this.setColour(120);
528
+ }
529
+ };
530
+ Blockly.Blocks['controls_while'] = {
531
+ init: function () {
532
+ this.appendValueInput('CONDITION').appendField('条件が真の間繰り返す');
533
+ this.appendStatementInput('DO').appendField('実行');
534
+ this.setPreviousStatement(true);
535
+ this.setNextStatement(true);
536
+ this.setColour(120);
537
+ }
538
+ };
539
+ Blockly.Blocks['controls_if'] = {
540
+ init: function () {
541
+ this.appendValueInput('IF0').appendField('もし');
542
+ this.appendStatementInput('DO0').appendField('なら');
543
+ this.appendStatementInput('ELSE').appendField('でなければ');
544
+ this.setPreviousStatement(true);
545
+ this.setNextStatement(true);
546
+ this.setColour(120);
547
+ }
548
+ };
549
+ Blockly.Blocks['repeat_times'] = {
550
+ init: function () {
551
+ this.appendValueInput('TIMES')
552
+ .setCheck('Number')
553
+ .appendField('繰り返し:');
554
+ this.appendStatementInput('DO')
555
+ .appendField('回');
556
+ this.setPreviousStatement(true);
557
+ this.setNextStatement(true);
558
+ this.setColour(120);
559
+ }
560
+ };
561
+ Blockly.Blocks['if_condition'] = {
562
+ init: function () {
563
+ this.appendValueInput('CONDITION')
564
+ .setCheck('Boolean')
565
+ .appendField('もし');
566
+ this.appendStatementInput('DO')
567
+ .appendField('なら');
568
+ this.setPreviousStatement(true);
569
+ this.setNextStatement(true);
570
+ this.setColour(120);
571
+ }
572
+ };
573
+ Blockly.Blocks['wait_until_condition'] = {
574
+ init: function () {
575
+ this.appendValueInput('CONDITION')
576
+ .setCheck('Boolean')
577
+ .appendField('条件が真になるまで待つ');
578
+ this.setPreviousStatement(true);
579
+ this.setNextStatement(true);
580
+ this.setColour(120);
581
+ }
582
+ };
583
+
584
+ // ピン
585
+ Blockly.Blocks['pin_mode'] = {
586
+ init: function () {
587
+ this.appendDummyInput()
588
+ .appendField('ピンのモードを設定:')
589
+ .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN')
590
+ .appendField(new Blockly.FieldDropdown([['出力', 'OUTPUT'], ['入力', 'INPUT'], ['入力プルアップ', 'INPUT_PULLUP']]), 'MODE');
591
+ this.setPreviousStatement(true);
592
+ this.setNextStatement(true);
593
+ this.setColour(160);
594
+ }
595
+ };
596
+ Blockly.Blocks['digital_write'] = {
597
+ init: function () {
598
+ this.appendDummyInput()
599
+ .appendField('デジタル出力:')
600
+ .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN')
601
+ .appendField(new Blockly.FieldDropdown([['HIGH', 'HIGH'], ['LOW', 'LOW']]), 'VALUE');
602
+ this.setPreviousStatement(true);
603
+ this.setNextStatement(true);
604
+ this.setColour(160);
605
+ }
606
+ };
607
+ Blockly.Blocks['digital_read'] = {
608
+ init: function () {
609
+ this.appendDummyInput()
610
+ .appendField('デジタル入力:')
611
+ .appendField(new Blockly.FieldNumber(0, 0, 53), 'PIN');
612
+ this.setOutput(true, 'Number');
613
+ this.setColour(160);
614
+ }
615
+ };
616
+ Blockly.Blocks['analog_read'] = {
617
+ init: function () {
618
+ this.appendDummyInput()
619
+ .appendField('アナログ入力:')
620
+ .appendField(new Blockly.FieldDropdown([
621
+ ['A0', 'A0'], ['A1', 'A1'], ['A2', 'A2'], ['A3', 'A3'],
622
+ ['A4', 'A4'], ['A5', 'A5'], ['A6', 'A6'], ['A7', 'A7'],
623
+ ['A8', 'A8'], ['A9', 'A9'], ['A10', 'A10'], ['A11', 'A11'],
624
+ ['A12', 'A12'], ['A13', 'A13'], ['A14', 'A14'], ['A15', 'A15']
625
+ ]), 'PIN');
626
+ this.setOutput(true, 'Number');
627
+ this.setColour(160);
628
+ }
629
+ };
630
+ Blockly.Blocks['analog_write'] = {
631
+ init: function () {
632
+ this.appendDummyInput()
633
+ .appendField('アナログ出力:')
634
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN');
635
+ this.appendValueInput('VALUE')
636
+ .setCheck('Number')
637
+ .appendField('値:');
638
+ this.setPreviousStatement(true);
639
+ this.setNextStatement(true);
640
+ this.setColour(160);
641
+ }
642
+ };
643
+
644
+ // テスト
645
+ Blockly.Blocks['logic_compare'] = {
646
+ init: function () {
647
+ this.appendValueInput('A').setCheck('Number');
648
+ this.appendDummyInput()
649
+ .appendField(new Blockly.FieldDropdown([['=', 'EQ'], ['≠', 'NEQ'], ['<', 'LT'], ['≤', 'LTE'], ['>', 'GT'], ['≥', 'GTE']]), 'OP');
650
+ this.appendValueInput('B').setCheck('Number');
651
+ this.setOutput(true, 'Boolean');
652
+ this.setColour(210);
653
+ }
654
+ };
655
+ Blockly.Blocks['logic_operation'] = {
656
+ init: function () {
657
+ this.appendValueInput('A').setCheck('Boolean');
658
+ this.appendDummyInput()
659
+ .appendField(new Blockly.FieldDropdown([['かつ', 'AND'], ['または', 'OR']]), 'OP');
660
+ this.appendValueInput('B').setCheck('Boolean');
661
+ this.setOutput(true, 'Boolean');
662
+ this.setColour(210);
663
+ }
664
+ };
665
+ Blockly.Blocks['string_compare'] = {
666
+ init: function () {
667
+ this.appendValueInput('A').setCheck('String');
668
+ this.appendDummyInput()
669
+ .appendField(new Blockly.FieldDropdown([['=', 'EQ'], ['≠', 'NEQ']]), 'OP');
670
+ this.appendValueInput('B').setCheck('String');
671
+ this.setOutput(true, 'Boolean');
672
+ this.setColour(210);
673
+ }
674
+ };
675
+
676
+ // 計算
677
+ Blockly.Blocks['math_arithmetic'] = {
678
+ init: function () {
679
+ this.appendValueInput('A').setCheck('Number');
680
+ this.appendDummyInput()
681
+ .appendField(new Blockly.FieldDropdown([['+', 'ADD'], ['-', 'MINUS'], ['×', 'MULTIPLY'], ['÷', 'DIVIDE']]), 'OP');
682
+ this.appendValueInput('B').setCheck('Number');
683
+ this.setOutput(true, 'Number');
684
+ this.setColour(230);
685
+ }
686
+ };
687
+ Blockly.Blocks['math_single'] = {
688
+ init: function () {
689
+ this.appendValueInput('NUM').setCheck('Number')
690
+ .appendField(new Blockly.FieldDropdown([['絶対値', 'ABS'], ['平方根', 'SQRT']]), 'OP');
691
+ this.setOutput(true, 'Number');
692
+ this.setColour(230);
693
+ }
694
+ };
695
+ Blockly.Blocks['math_trig'] = {
696
+ init: function () {
697
+ this.appendValueInput('NUM').setCheck('Number')
698
+ .appendField(new Blockly.FieldDropdown([['sin', 'SIN'], ['cos', 'COS'], ['tan', 'TAN']]), 'OP');
699
+ this.setOutput(true, 'Number');
700
+ this.setColour(230);
701
+ }
702
+ };
703
+ Blockly.Blocks['random_number'] = {
704
+ init: function () {
705
+ this.appendValueInput('MIN')
706
+ .setCheck('Number')
707
+ .appendField('乱数:');
708
+ this.appendValueInput('MAX')
709
+ .setCheck('Number')
710
+ .appendField('から');
711
+ this.appendDummyInput()
712
+ .appendField('まで');
713
+ this.setOutput(true, 'Number');
714
+ this.setColour(230);
715
+ }
716
+ };
717
+ Blockly.Blocks['divide'] = {
718
+ init: function () {
719
+ this.appendValueInput('NUM')
720
+ .setCheck('Number')
721
+ .appendField('');
722
+ this.appendValueInput('DIV')
723
+ .setCheck('Number')
724
+ .appendField('を');
725
+ this.appendDummyInput()
726
+ .appendField('で割った値');
727
+ this.setOutput(true, 'Number');
728
+ this.setColour(230);
729
+ }
730
+ };
731
+ Blockly.Blocks['number_input'] = {
732
+ init: function () {
733
+ this.appendDummyInput()
734
+ .appendField('数値:')
735
+ .appendField(new Blockly.FieldNumber(0), 'VALUE');
736
+ this.setOutput(true, 'Number');
737
+ this.setColour(230);
738
+ }
739
+ };
740
+ Blockly.Blocks['string_input'] = {
741
+ init: function () {
742
+ this.appendDummyInput()
743
+ .appendField('文字列:')
744
+ .appendField(new Blockly.FieldTextInput('Hello'), 'TEXT');
745
+ this.setOutput(true, 'String');
746
+ this.setColour(230);
747
+ }
748
+ };
749
+ Blockly.Blocks['text_input'] = {
750
+ init: function () {
751
+ this.appendDummyInput()
752
+ .appendField('テキスト:')
753
+ .appendField(new Blockly.FieldTextInput('Hello'), 'TEXT');
754
+ this.setOutput(true, 'String');
755
+ this.setColour(230);
756
+ }
757
+ };
758
+ Blockly.Blocks['variable_set_number'] = {
759
+ init: function () {
760
+ this.appendDummyInput()
761
+ .appendField('数値変数')
762
+ .appendField(new Blockly.FieldVariable(null), 'VAR')
763
+ .appendField('に代入:');
764
+ this.appendValueInput('VALUE')
765
+ .setCheck('Number');
766
+ this.setPreviousStatement(true);
767
+ this.setNextStatement(true);
768
+ this.setColour(230);
769
+ }
770
+ };
771
+ Blockly.Blocks['variable_set_string'] = {
772
+ init: function () {
773
+ this.appendDummyInput()
774
+ .appendField('文字列変数')
775
+ .appendField(new Blockly.FieldVariable(null), 'VAR')
776
+ .appendField('に代入:');
777
+ this.appendValueInput('TEXT')
778
+ .setCheck('String');
779
+ this.setPreviousStatement(true);
780
+ this.setNextStatement(true);
781
+ this.setColour(230);
782
+ }
783
+ };
784
+
785
+ // 変数
786
+ Blockly.Blocks['variable_declare_int'] = {
787
+ init: function () {
788
+ this.appendDummyInput()
789
+ .appendField('整数変数宣言:')
790
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
791
+ this.setPreviousStatement(true);
792
+ this.setNextStatement(true);
793
+ this.setColour(260);
794
+ }
795
+ };
796
+ Blockly.Blocks['variable_set_int'] = {
797
+ init: function () {
798
+ this.appendValueInput('VALUE')
799
+ .setCheck('Number')
800
+ .appendField('整数変数')
801
+ .appendField(new Blockly.FieldVariable(null), 'VAR')
802
+ .appendField('に代入:');
803
+ this.setPreviousStatement(true);
804
+ this.setNextStatement(true);
805
+ this.setColour(260);
806
+ }
807
+ };
808
+ Blockly.Blocks['variable_get_int'] = {
809
+ init: function () {
810
+ this.appendDummyInput()
811
+ .appendField('整数変数')
812
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
813
+ this.setOutput(true, 'Number');
814
+ this.setColour(260);
815
+ }
816
+ };
817
+ Blockly.Blocks['int_declare'] = {
818
+ init: function () {
819
+ this.appendDummyInput()
820
+ .appendField('int変数宣言:')
821
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
822
+ this.setPreviousStatement(true);
823
+ this.setNextStatement(true);
824
+ this.setColour(260);
825
+ }
826
+ };
827
+ Blockly.Blocks['int_set'] = {
828
+ init: function () {
829
+ this.appendValueInput('VALUE')
830
+ .setCheck('Number')
831
+ .appendField('int変数')
832
+ .appendField(new Blockly.FieldVariable(null), 'VAR')
833
+ .appendField('に代入:');
834
+ this.setPreviousStatement(true);
835
+ this.setNextStatement(true);
836
+ this.setColour(260);
837
+ }
838
+ };
839
+ Blockly.Blocks['int_get'] = {
840
+ init: function () {
841
+ this.appendDummyInput()
842
+ .appendField('int変数')
843
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
844
+ this.setOutput(true, 'Number');
845
+ this.setColour(260);
846
+ }
847
+ };
848
+ Blockly.Blocks['float_declare'] = {
849
+ init: function () {
850
+ this.appendDummyInput()
851
+ .appendField('float変数宣言:')
852
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
853
+ this.setPreviousStatement(true);
854
+ this.setNextStatement(true);
855
+ this.setColour(260);
856
+ }
857
+ };
858
+ Blockly.Blocks['float_set'] = {
859
+ init: function () {
860
+ this.appendValueInput('VALUE')
861
+ .setCheck('Number')
862
+ .appendField('float変数')
863
+ .appendField(new Blockly.FieldVariable(null), 'VAR')
864
+ .appendField('に代入:');
865
+ this.setPreviousStatement(true);
866
+ this.setNextStatement(true);
867
+ this.setColour(260);
868
+ }
869
+ };
870
+ Blockly.Blocks['float_get'] = {
871
+ init: function () {
872
+ this.appendDummyInput()
873
+ .appendField('float変数')
874
+ .appendField(new Blockly.FieldVariable(null), 'VAR');
875
+ this.setOutput(true, 'Number');
876
+ this.setColour(260);
877
+ }
878
+ };
879
+
880
+ // Generic Hardware
881
+ Blockly.Blocks['servo_write'] = {
882
+ init: function () {
883
+ this.appendDummyInput()
884
+ .appendField('サーボ:')
885
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN');
886
+ this.appendValueInput('ANGLE')
887
+ .setCheck('Number')
888
+ .appendField('角度:');
889
+ this.setPreviousStatement(true);
890
+ this.setNextStatement(true);
891
+ this.setColour(290);
892
+ }
893
+ };
894
+ Blockly.Blocks['ultrasonic_read'] = {
895
+ init: function () {
896
+ this.appendDummyInput()
897
+ .appendField('超音波センサ: トリガ')
898
+ .appendField(new Blockly.FieldNumber(12, 0, 53), 'TRIG')
899
+ .appendField('エコー')
900
+ .appendField(new Blockly.FieldNumber(11, 0, 53), 'ECHO');
901
+ this.setPreviousStatement(true);
902
+ this.setNextStatement(true);
903
+ this.setColour(290);
904
+ }
905
+ };
906
+ Blockly.Blocks['ultrasonic_distance'] = {
907
+ init: function () {
908
+ this.appendDummyInput()
909
+ .appendField('超音波センサ')
910
+ .appendField('トリガ')
911
+ .appendField(new Blockly.FieldNumber(12, 0, 53), 'TRIG');
912
+ this.setOutput(true, 'Number');
913
+ this.setColour(290);
914
+ }
915
+ };
916
+ Blockly.Blocks['lcd_print'] = {
917
+ init: function () {
918
+ this.appendDummyInput()
919
+ .appendField('LCD表示 ピン RS:')
920
+ .appendField(new Blockly.FieldNumber(8, 0, 53), 'RS')
921
+ .appendField('E:')
922
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'E')
923
+ .appendField('D4:')
924
+ .appendField(new Blockly.FieldNumber(4, 0, 53), 'D4');
925
+ this.appendDummyInput()
926
+ .appendField('D5:')
927
+ .appendField(new Blockly.FieldNumber(5, 0, 53), 'D5')
928
+ .appendField('D6:')
929
+ .appendField(new Blockly.FieldNumber(6, 0, 53), 'D6')
930
+ .appendField('D7:')
931
+ .appendField(new Blockly.FieldNumber(7, 0, 53), 'D7');
932
+ this.appendDummyInput()
933
+ .appendField('列数:')
934
+ .appendField(new Blockly.FieldNumber(16, 1), 'COLS')
935
+ .appendField('行数:')
936
+ .appendField(new Blockly.FieldNumber(2, 1), 'ROWS');
937
+ this.appendDummyInput()
938
+ .appendField('カーソル 列:')
939
+ .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_COL')
940
+ .appendField('行:')
941
+ .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_ROW');
942
+ this.appendValueInput('TEXT')
943
+ .appendField('テキスト:');
944
+ this.setPreviousStatement(true);
945
+ this.setNextStatement(true);
946
+ this.setColour(290);
947
+ }
948
+ };
949
+ Blockly.Blocks['lcd_print_value'] = {
950
+ init: function () {
951
+ this.appendDummyInput()
952
+ .appendField('LCD数値表示 ピン RS:')
953
+ .appendField(new Blockly.FieldNumber(8, 0, 53), 'RS')
954
+ .appendField('E:')
955
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'E')
956
+ .appendField('D4:')
957
+ .appendField(new Blockly.FieldNumber(4, 0, 53), 'D4');
958
+ this.appendDummyInput()
959
+ .appendField('D5:')
960
+ .appendField(new Blockly.FieldNumber(5, 0, 53), 'D5')
961
+ .appendField('D6:')
962
+ .appendField(new Blockly.FieldNumber(6, 0, 53), 'D6')
963
+ .appendField('D7:')
964
+ .appendField(new Blockly.FieldNumber(7, 0, 53), 'D7');
965
+ this.appendDummyInput()
966
+ .appendField('列数:')
967
+ .appendField(new Blockly.FieldNumber(16, 1), 'COLS')
968
+ .appendField('行数:')
969
+ .appendField(new Blockly.FieldNumber(2, 1), 'ROWS');
970
+ this.appendDummyInput()
971
+ .appendField('カーソル 列:')
972
+ .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_COL')
973
+ .appendField('行:')
974
+ .appendField(new Blockly.FieldNumber(0, 0), 'CURSOR_ROW');
975
+ this.appendValueInput('VALUE')
976
+ .setCheck('Number')
977
+ .appendField('数値:');
978
+ this.setPreviousStatement(true);
979
+ this.setNextStatement(true);
980
+ this.setColour(290);
981
+ }
982
+ };
983
+ Blockly.Blocks['lcd_clear'] = {
984
+ init: function () {
985
+ this.appendDummyInput()
986
+ .appendField('LCDクリア');
987
+ this.setPreviousStatement(true);
988
+ this.setNextStatement(true);
989
+ this.setColour(290);
990
+ }
991
+ };
992
+ Blockly.Blocks['seven_segment_display'] = {
993
+ init: function () {
994
+ this.appendDummyInput()
995
+ .appendField('7セグメントLED表示 ピン a:')
996
+ .appendField(new Blockly.FieldNumber(2, 0, 53), 'PIN_A')
997
+ .appendField('b:')
998
+ .appendField(new Blockly.FieldNumber(3, 0, 53), 'PIN_B')
999
+ .appendField('c:')
1000
+ .appendField(new Blockly.FieldNumber(4, 0, 53), 'PIN_C');
1001
+ this.appendDummyInput()
1002
+ .appendField('d:')
1003
+ .appendField(new Blockly.FieldNumber(5, 0, 53), 'PIN_D')
1004
+ .appendField('e:')
1005
+ .appendField(new Blockly.FieldNumber(6, 0, 53), 'PIN_E')
1006
+ .appendField('f:')
1007
+ .appendField(new Blockly.FieldNumber(7, 0, 53), 'PIN_F');
1008
+ this.appendDummyInput()
1009
+ .appendField('g:')
1010
+ .appendField(new Blockly.FieldNumber(8, 0, 53), 'PIN_G');
1011
+ this.appendValueInput('NUMBER')
1012
+ .setCheck('Number')
1013
+ .appendField('数字:');
1014
+ this.setPreviousStatement(true);
1015
+ this.setNextStatement(true);
1016
+ this.setColour(290);
1017
+ }
1018
+ };
1019
+ Blockly.Blocks['tone'] = {
1020
+ init: function () {
1021
+ this.appendDummyInput()
1022
+ .appendField('トーン出力 ピン:')
1023
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN');
1024
+ this.appendValueInput('FREQUENCY')
1025
+ .setCheck('Number')
1026
+ .appendField('周波数(Hz):');
1027
+ this.setPreviousStatement(true);
1028
+ this.setNextStatement(true);
1029
+ this.setColour(290);
1030
+ }
1031
+ };
1032
+ Blockly.Blocks['noTone'] = {
1033
+ init: function () {
1034
+ this.appendDummyInput()
1035
+ .appendField('トーン停止 ピン:')
1036
+ .appendField(new Blockly.FieldNumber(9, 0, 53), 'PIN');
1037
+ this.setPreviousStatement(true);
1038
+ this.setNextStatement(true);
1039
+ this.setColour(290);
1040
+ }
1041
+ };
1042
+
1043
+ // 通信
1044
+ Blockly.Blocks['serial_begin'] = {
1045
+ init: function () {
1046
+ this.appendDummyInput()
1047
+ .appendField('シリアル開始:')
1048
+ .appendField(new Blockly.FieldNumber(9600), 'BAUD');
1049
+ this.setPreviousStatement(true);
1050
+ this.setNextStatement(true);
1051
+ this.setColour(320);
1052
+ }
1053
+ };
1054
+ Blockly.Blocks['serial_print'] = {
1055
+ init: function () {
1056
+ this.appendValueInput('TEXT')
1057
+ .appendField('シリアル出力(改行なし):');
1058
+ this.setPreviousStatement(true);
1059
+ this.setNextStatement(true);
1060
+ this.setColour(320);
1061
+ }
1062
+ };
1063
+ Blockly.Blocks['serial_print_value'] = {
1064
+ init: function () {
1065
+ this.appendValueInput('VALUE')
1066
+ .setCheck('Number')
1067
+ .appendField('シリアル出力(数値、改行なし):');
1068
+ this.setPreviousStatement(true);
1069
+ this.setNextStatement(true);
1070
+ this.setColour(320);
1071
+ }
1072
+ };
1073
+ Blockly.Blocks['serial_println'] = {
1074
+ init: function () {
1075
+ this.appendValueInput('TEXT')
1076
+ .appendField('シリアル出力:');
1077
+ this.setPreviousStatement(true);
1078
+ this.setNextStatement(true);
1079
+ this.setColour(320);
1080
+ }
1081
+ };
1082
+ Blockly.Blocks['serial_println_value'] = {
1083
+ init: function () {
1084
+ this.appendValueInput('VALUE')
1085
+ .setCheck('Number')
1086
+ .appendField('シリアル出力(数値):');
1087
+ this.setPreviousStatement(true);
1088
+ this.setNextStatement(true);
1089
+ this.setColour(320);
1090
+ }
1091
+ };
1092
+ Blockly.Blocks['serial_read_number'] = {
1093
+ init: function () {
1094
+ this.appendDummyInput()
1095
+ .appendField('シリアル入力(数値)');
1096
+ this.setOutput(true, 'Number');
1097
+ this.setColour(320);
1098
+ }
1099
+ };
1100
+ Blockly.Blocks['serial_read_string'] = {
1101
+ init: function () {
1102
+ this.appendDummyInput()
1103
+ .appendField('シリアル入力(文字列)');
1104
+ this.setOutput(true, 'String');
1105
+ this.setColour(320);
1106
+ }
1107
+ };
1108
+
1109
+ // 拡張
1110
+ Blockly.Blocks['custom_code'] = {
1111
+ init: function () {
1112
+ this.appendDummyInput()
1113
+ .appendField('カスタムコード:')
1114
+ .appendField(new Blockly.FieldTextInput(''), 'CODE');
1115
+ this.setPreviousStatement(true);
1116
+ this.setNextStatement(true);
1117
+ this.setColour(350);
1118
+ }
1119
+ };
1120
+ Blockly.Blocks['custom_string'] = {
1121
+ init: function () {
1122
+ this.appendDummyInput()
1123
+ .appendField('カスタム文字列:')
1124
+ .appendField(new Blockly.FieldTextInput(''), 'TEXT');
1125
+ this.setOutput(true, 'String');
1126
+ this.setColour(350);
1127
+ }
1128
+ };
1129
+ Blockly.Blocks['custom_number'] = {
1130
+ init: function () {
1131
+ this.appendDummyInput()
1132
+ .appendField('カスタム数値:')
1133
+ .appendField(new Blockly.FieldTextInput(''), 'NUMBER');
1134
+ this.setOutput(true, 'Number');
1135
+ this.setColour(350);
1136
+ }
1137
+ };
1138
+
1139
+ // Blocklyワークスペースを初期化
1140
+ const workspace = Blockly.inject('block-area', {
1141
+ toolbox: document.getElementById('toolbox'),
1142
+ scrollbars: true,
1143
+ trashcan: true,
1144
+ sounds: true,
1145
+ zoom: {
1146
+ controls: false, // デフォルトのズームコントロールを無効化
1147
+ wheel: false,
1148
+ startScale: 1.0,
1149
+ maxScale: 2.0,
1150
+ minScale: 0.5,
1151
+ scaleSpeed: 1.2
1152
+ }
1153
+ });
1154
+
1155
+ // ズームコントロールを手動で追加(インラインSVGを使用)
1156
+ const zoomControls = document.createElement('div');
1157
+ zoomControls.className = 'blocklyZoom';
1158
+ zoomControls.innerHTML = `
1159
+ <svg id="zoom-in" viewBox="0 0 32 32" title="拡大">
1160
+ <circle cx="16" cy="16" r="10" fill="none" stroke="#000" stroke-width="2"/>
1161
+ <path d="M12 16 h8 M16 12 v8" stroke="#000" stroke-width="2"/>
1162
+ <line x1="22" y1="22" x2="28" y2="28" stroke="#000" stroke-width="2"/>
1163
+ </svg>
1164
+ <svg id="zoom-out" viewBox="0 0 32 32" title="縮小">
1165
+ <circle cx="16" cy="16" r="10" fill="none" stroke="#000" stroke-width="2"/>
1166
+ <path d="M12 16 h8" stroke="#000" stroke-width="2"/>
1167
+ <line x1="22" y1="22" x2="28" y2="28" stroke="#000" stroke-width="2"/>
1168
+ </svg>
1169
+ <svg id="zoom-reset" viewBox="0 0 32 32" title="中央寄せ">
1170
+ <path d="M8 16 h16 M16 8 v16" stroke="#000" stroke-width="2"/>
1171
+ <path d="M8 12 l-4 4 l4 4 M24 12 l4 4 l-4 4" fill="none" stroke="#000" stroke-width="2"/>
1172
+ </svg>
1173
+ `;
1174
+ document.getElementById('block-area').appendChild(zoomControls);
1175
+
1176
+ // ズームと中央寄せのイベントリスナー
1177
+ document.getElementById('zoom-in').addEventListener('click', function () {
1178
+ workspace.zoomCenter(1); // スケールを増加(ズームイン)
1179
+ });
1180
+
1181
+ document.getElementById('zoom-out').addEventListener('click', function () {
1182
+ workspace.zoomCenter(-1); // スケールを減少(ズームアウト)
1183
+ });
1184
+
1185
+ document.getElementById('zoom-reset').addEventListener('click', function () {
1186
+ const topBlocks = workspace.getTopBlocks(true);
1187
+ if (topBlocks.length > 0) {
1188
+ workspace.centerOnBlock(topBlocks[0].id);
1189
+ } else {
1190
+ workspace.scrollCenter();
1191
+ }
1192
+ });
1193
+
1194
+ // コピーボタンのイベントリスナー
1195
+ document.getElementById('copy-button').addEventListener('click', function () {
1196
+ const code = document.getElementById('generated-code').textContent;
1197
+ navigator.clipboard.writeText(code).then(() => {
1198
+ const copyMessage = document.getElementById('copy-message');
1199
+ copyMessage.style.display = 'block';
1200
+ setTimeout(() => {
1201
+ copyMessage.style.display = 'none';
1202
+ }, 3000);
1203
+ }).catch(err => {
1204
+ console.error('コードのコピーに失敗しました:', err);
1205
+ });
1206
+ });
1207
+
1208
+ // URLからワークスペースを復元
1209
+ function loadWorkspaceFromUrl() {
1210
+ const urlParams = new URLSearchParams(window.location.search);
1211
+ const compressed = urlParams.get('blocks');
1212
+ if (compressed) {
1213
+ try {
1214
+ const binaryString = atob(compressed);
1215
+ const bytes = new Uint8Array(binaryString.length);
1216
+ for (let i = 0; i < binaryString.length; i++) {
1217
+ bytes[i] = binaryString.charCodeAt(i);
1218
+ }
1219
+ const xmlString = pako.inflate(bytes, { to: 'string' });
1220
+ const xml = Blockly.utils.xml.textToDom(xmlString);
1221
+ workspace.clear();
1222
+ Blockly.Xml.domToWorkspace(xml, workspace);
1223
+ } catch (e) {
1224
+ console.error('ワークスペースの復元に失敗しました:', e);
1225
+ }
1226
+ }
1227
+ }
1228
+
1229
+ // ワークスペースをURLに保存
1230
+ function saveWorkspaceToUrl() {
1231
+ try {
1232
+ const xml = Blockly.Xml.workspaceToDom(workspace);
1233
+ const xmlString = Blockly.Xml.domToText(xml);
1234
+ const compressed = pako.gzip(xmlString, { to: 'string' });
1235
+ const base64 = btoa(String.fromCharCode.apply(null, compressed));
1236
+ const url = new URL(window.location);
1237
+ url.searchParams.set('blocks', base64);
1238
+ history.pushState({}, '', url);
1239
+ } catch (e) {
1240
+ console.error('ワークスペースの保存に失敗しました:', e);
1241
+ }
1242
+ }
1243
+
1244
+ // Arduinoコード生成ロジック
1245
+ function generateArduinoCode() {
1246
+ let includes = new Set();
1247
+ let variables = new Set();
1248
+ let servoObjects = new Set();
1249
+ let servoSetup = new Set();
1250
+ let lcdObjects = new Set();
1251
+ let lcdSetup = new Set();
1252
+ let sevenSegmentSetup = new Set();
1253
+ let code = '';
1254
+ const topBlocks = workspace.getTopBlocks(true);
1255
+ let lcdPinConfig = null;
1256
+
1257
+ function collectDependencies(block) {
1258
+ if (!block) return;
1259
+ let currentBlock = block;
1260
+ while (currentBlock) {
1261
+ if (currentBlock.type === 'variable_declare_int' || currentBlock.type === 'variable_set_int' || currentBlock.type === 'variable_get_int') {
1262
+ const varField = currentBlock.getField('VAR');
1263
+ if (varField && workspace.getVariableMap()) {
1264
+ const variable = varField.getVariable();
1265
+ if (variable) {
1266
+ const varName = variable.name;
1267
+ if (varName) {
1268
+ variables.add(`uint8_t ${varName};`);
1269
+ }
1270
+ }
1271
+ }
1272
+ } else if (currentBlock.type === 'int_declare' || currentBlock.type === 'int_set' || currentBlock.type === 'int_get') {
1273
+ const varField = currentBlock.getField('VAR');
1274
+ if (varField && workspace.getVariableMap()) {
1275
+ const variable = varField.getVariable();
1276
+ if (variable) {
1277
+ const varName = variable.name;
1278
+ if (varName) {
1279
+ variables.add(`int ${varName};`);
1280
+ }
1281
+ }
1282
+ }
1283
+ } else if (currentBlock.type === 'float_declare' || currentBlock.type === 'float_set' || currentBlock.type === 'float_get') {
1284
+ const varField = currentBlock.getField('VAR');
1285
+ if (varField && workspace.getVariableMap()) {
1286
+ const variable = varField.getVariable();
1287
+ if (variable) {
1288
+ const varName = variable.name;
1289
+ if (varName) {
1290
+ variables.add(`float ${varName};`);
1291
+ }
1292
+ }
1293
+ }
1294
+ } else if (currentBlock.type === 'variable_set_number' || currentBlock.type === 'variable_set_string') {
1295
+ const varField = currentBlock.getField('VAR');
1296
+ if (varField && workspace.getVariableMap()) {
1297
+ const variable = varField.getVariable();
1298
+ if (variable) {
1299
+ const varName = variable.name;
1300
+ if (varName) {
1301
+ if (currentBlock.type === 'variable_set_number') {
1302
+ variables.add(`float ${varName};`);
1303
+ } else if (currentBlock.type === 'variable_set_string') {
1304
+ variables.add(`String ${varName};`);
1305
+ }
1306
+ }
1307
+ }
1308
+ }
1309
+ } else if (currentBlock.type === 'servo_write') {
1310
+ const pinServo = currentBlock.getFieldValue('PIN');
1311
+ includes.add('#include <Servo.h>');
1312
+ servoObjects.add(`Servo servo_${pinServo};`);
1313
+ servoSetup.add(`servo_${pinServo}.attach(${pinServo});`);
1314
+ } else if (currentBlock.type === 'lcd_print' || currentBlock.type === 'lcd_print_value') {
1315
+ includes.add('#include <LiquidCrystal.h>');
1316
+ const rs = currentBlock.getFieldValue('RS');
1317
+ const e = currentBlock.getFieldValue('E');
1318
+ const d4 = currentBlock.getFieldValue('D4');
1319
+ const d5 = currentBlock.getFieldValue('D5');
1320
+ const d6 = currentBlock.getFieldValue('D6');
1321
+ const d7 = currentBlock.getFieldValue('D7');
1322
+ const cols = currentBlock.getFieldValue('COLS');
1323
+ const rows = currentBlock.getFieldValue('ROWS');
1324
+ const newPinConfig = `${rs},${e},${d4},${d5},${d6},${d7}`;
1325
+ if (!lcdPinConfig) {
1326
+ lcdPinConfig = newPinConfig;
1327
+ lcdObjects.add(`LiquidCrystal lcd(${rs}, ${e}, ${d4}, ${d5}, ${d6}, ${d7});`);
1328
+ lcdSetup.add(`lcd.begin(${cols}, ${rows});`);
1329
+ lcdSetup.add(`lcd.clear();`);
1330
+ } else if (lcdPinConfig !== newPinConfig) {
1331
+ console.warn(`LCDピンの設定が異なります。最初の設定(${lcdPinConfig})を使用します。`);
1332
+ }
1333
+ } else if (currentBlock.type === 'lcd_clear') {
1334
+ includes.add('#include <LiquidCrystal.h>');
1335
+ if (!lcdPinConfig) {
1336
+ lcdPinConfig = '8,9,4,5,6,7';
1337
+ lcdObjects.add(`LiquidCrystal lcd(8, 9, 4, 5, 6, 7);`);
1338
+ lcdSetup.add(`lcd.begin(16, 2);`);
1339
+ lcdSetup.add(`lcd.clear();`);
1340
+ }
1341
+ } else if (currentBlock.type === 'seven_segment_display') {
1342
+ const pinA = currentBlock.getFieldValue('PIN_A');
1343
+ const pinB = currentBlock.getFieldValue('PIN_B');
1344
+ const pinC = currentBlock.getFieldValue('PIN_C');
1345
+ const pinD = currentBlock.getFieldValue('PIN_D');
1346
+ const pinE = currentBlock.getFieldValue('PIN_E');
1347
+ const pinF = currentBlock.getFieldValue('PIN_F');
1348
+ const pinG = currentBlock.getFieldValue('PIN_G');
1349
+ sevenSegmentSetup.add(`pinMode(${pinA}, OUTPUT);`);
1350
+ sevenSegmentSetup.add(`pinMode(${pinB}, OUTPUT);`);
1351
+ sevenSegmentSetup.add(`pinMode(${pinC}, OUTPUT);`);
1352
+ sevenSegmentSetup.add(`pinMode(${pinD}, OUTPUT);`);
1353
+ sevenSegmentSetup.add(`pinMode(${pinE}, OUTPUT);`);
1354
+ sevenSegmentSetup.add(`pinMode(${pinF}, OUTPUT);`);
1355
+ sevenSegmentSetup.add(`pinMode(${pinG}, OUTPUT);`);
1356
+ } else if (currentBlock.type === 'ultrasonic_read') {
1357
+ const trig = currentBlock.getFieldValue('TRIG');
1358
+ const echo = currentBlock.getFieldValue('ECHO');
1359
+ variables.add(`long duration_${trig};`);
1360
+ variables.add(`int distance_${trig};`);
1361
+ sevenSegmentSetup.add(`pinMode(${trig}, OUTPUT);`);
1362
+ sevenSegmentSetup.add(`pinMode(${echo}, INPUT);`);
1363
+ } else if (currentBlock.type === 'tone') {
1364
+ const pin = currentBlock.getFieldValue('PIN');
1365
+ sevenSegmentSetup.add(`pinMode(${pin}, OUTPUT);`);
1366
+ }
1367
+
1368
+ if (currentBlock.getInput('DO')) collectDependencies(currentBlock.getInputTargetBlock('DO'));
1369
+ if (currentBlock.getInput('DO0')) collectDependencies(currentBlock.getInputTargetBlock('DO0'));
1370
+ if (currentBlock.getInput('ELSE')) collectDependencies(currentBlock.getInputTargetBlock('ELSE'));
1371
+ if (currentBlock.getInput('SETUP_CODE')) collectDependencies(currentBlock.getInputTargetBlock('SETUP_CODE'));
1372
+ if (currentBlock.getInput('LOOP_CODE')) collectDependencies(currentBlock.getInputTargetBlock('LOOP_CODE'));
1373
+ if (currentBlock.getInput('VALUE')) collectDependencies(currentBlock.getInputTargetBlock('VALUE'));
1374
+ if (currentBlock.getInput('TEXT')) collectDependencies(currentBlock.getInputTargetBlock('TEXT'));
1375
+ if (currentBlock.getInput('NUMBER')) collectDependencies(currentBlock.getInputTargetBlock('NUMBER'));
1376
+ if (currentBlock.getInput('FREQUENCY')) collectDependencies(currentBlock.getInputTargetBlock('FREQUENCY'));
1377
+ if (currentBlock.getInput('ANGLE')) collectDependencies(currentBlock.getInputTargetBlock('ANGLE'));
1378
+ if (currentBlock.getInput('TIME')) collectDependencies(currentBlock.getInputTargetBlock('TIME'));
1379
+ if (currentBlock.getInput('A')) collectDependencies(currentBlock.getInputTargetBlock('A'));
1380
+ if (currentBlock.getInput('B')) collectDependencies(currentBlock.getInputTargetBlock('B'));
1381
+ currentBlock = currentBlock.getNextBlock();
1382
+ }
1383
+ }
1384
+
1385
+ topBlocks.forEach(block => collectDependencies(block));
1386
+
1387
+ if (includes.size > 0) {
1388
+ code += Array.from(includes).join('\n') + '\n\n';
1389
+ }
1390
+
1391
+ if (variables.size > 0 || servoObjects.size > 0 || lcdObjects.size > 0) {
1392
+ code += [...variables, ...servoObjects, ...lcdObjects].join('\n') + '\n\n';
1393
+ }
1394
+
1395
+ topBlocks.forEach(block => {
1396
+ if (block.type === 'setup') {
1397
+ code += 'void setup() {\n';
1398
+ if (servoSetup.size > 0 || lcdSetup.size > 0 || sevenSegmentSetup.size > 0) {
1399
+ code += ` ${[...servoSetup, ...lcdSetup, ...sevenSegmentSetup].join('\n ')}\n`;
1400
+ }
1401
+ const setupCode = generateCodeForBlock(block.getInputTargetBlock('SETUP_CODE'));
1402
+ code += setupCode ? ` ${setupCode.replace(/\n/g, '\n ')}` : '';
1403
+ code += '\n}\n\n';
1404
+ } else if (block.type === 'loop') {
1405
+ code += 'void loop() {\n';
1406
+ const loopCode = generateCodeForBlock(block.getInputTargetBlock('LOOP_CODE'));
1407
+ code += loopCode ? ` ${loopCode.replace(/\n/g, '\n ')}` : '';
1408
+ code += '\n}\n';
1409
+ }
1410
+ });
1411
+
1412
+ return code || '// コードが生成されていません';
1413
+ }
1414
+
1415
+ // Arduinoコード生成ロジック内のgenerateValueCode関数
1416
+ function generateValueCode(block) {
1417
+ if (!block) return '';
1418
+ switch (block.type) {
1419
+ case 'digital_read':
1420
+ const pinDr = block.getFieldValue('PIN');
1421
+ return `digitalRead(${pinDr})`;
1422
+ case 'analog_read':
1423
+ const pinAr = block.getFieldValue('PIN');
1424
+ return `analogRead(${pinAr})`;
1425
+ case 'serial_read_number':
1426
+ return `Serial.parseInt()`;
1427
+ case 'serial_read_string':
1428
+ return `Serial.readString()`; // クリーンアップせず、そのまま返す
1429
+ case 'logic_compare':
1430
+ const aComp = generateValueCode(block.getInputTargetBlock('A')) || '0';
1431
+ const opComp = block.getFieldValue('OP');
1432
+ const bComp = generateValueCode(block.getInputTargetBlock('B')) || '0';
1433
+ const operators = { 'EQ': '==', 'NEQ': '!=', 'LT': '<', 'LTE': '<=', 'GT': '>', 'GTE': '>=' };
1434
+ return `(${aComp} ${operators[opComp]} ${bComp})`;
1435
+ case 'string_compare':
1436
+ let aStr = generateValueCode(block.getInputTargetBlock('A')) || '""';
1437
+ let bStr = generateValueCode(block.getInputTargetBlock('B')) || '""';
1438
+ const opStr = block.getFieldValue('OP');
1439
+ // Serial.readString()の場合、クリーンアップしない
1440
+ if (block.getInputTargetBlock('A')?.type !== 'serial_read_string') {
1441
+ aStr = cleanString(aStr);
1442
+ }
1443
+ if (block.getInputTargetBlock('B')?.type !== 'serial_read_string') {
1444
+ bStr = cleanString(bStr);
1445
+ }
1446
+ if (opStr === 'EQ') {
1447
+ return `(${aStr} == ${bStr})`;
1448
+ } else { // NEQ
1449
+ return `(${aStr} != ${bStr})`;
1450
+ }
1451
+ case 'logic_operation':
1452
+ const aLogic = generateValueCode(block.getInputTargetBlock('A')) || 'true';
1453
+ const opLogic = block.getFieldValue('OP');
1454
+ const bLogic = generateValueCode(block.getInputTargetBlock('B')) || 'true';
1455
+ const logicOps = { 'AND': '&&', 'OR': '||' };
1456
+ return `(${aLogic} ${logicOps[opLogic]} ${bLogic})`;
1457
+ case 'math_arithmetic':
1458
+ const aMath = generateValueCode(block.getInputTargetBlock('A')) || '0';
1459
+ const opMath = block.getFieldValue('OP');
1460
+ const bMath = generateValueCode(block.getInputTargetBlock('B')) || '0';
1461
+ const mathOps = { 'ADD': '+', 'MINUS': '-', 'MULTIPLY': '*', 'DIVIDE': '/' };
1462
+ return `(${aMath} ${mathOps[opMath]} ${bMath})`;
1463
+ case 'math_single':
1464
+ const numSingle = generateValueCode(block.getInputTargetBlock('NUM')) || '0';
1465
+ const opSingle = block.getFieldValue('OP');
1466
+ return `${opSingle.toLowerCase()}(${numSingle})`;
1467
+ case 'math_trig':
1468
+ const numTrig = generateValueCode(block.getInputTargetBlock('NUM')) || '0';
1469
+ const opTrig = block.getFieldValue('OP');
1470
+ return `${opTrig.toLowerCase()}(${numTrig})`;
1471
+ case 'random_number':
1472
+ const min = generateValueCode(block.getInputTargetBlock('MIN')) || '0';
1473
+ const max = generateValueCode(block.getInputTargetBlock('MAX')) || '100';
1474
+ return `random(${min}, ${max})`;
1475
+ case 'divide':
1476
+ const num = generateValueCode(block.getInputTargetBlock('NUM')) || '10';
1477
+ const div = generateValueCode(block.getInputTargetBlock('DIV')) || '2';
1478
+ return `(${num} / ${div})`;
1479
+ case 'number_input':
1480
+ const numberValue = block.getFieldValue('VALUE');
1481
+ return `${numberValue}`;
1482
+ case 'string_input':
1483
+ const stringValue = block.getFieldValue('TEXT');
1484
+ return `"${stringValue.replace(/"/g, '\\"')}"`; // 通常の文字列はクリーンアップ
1485
+ case 'text_input':
1486
+ const textValue = block.getFieldValue('TEXT');
1487
+ return `"${textValue.replace(/"/g, '\\"')}"`; // 通常の文字列はクリーンアップ
1488
+ case 'custom_string':
1489
+ const customStringValue = block.getFieldValue('TEXT');
1490
+ return `"${customStringValue.replace(/"/g, '\\"')}"`;
1491
+ case 'custom_number':
1492
+ const customNumberValue = block.getFieldValue('NUMBER');
1493
+ return `${customNumberValue}`; // そのまま数値として扱う
1494
+ case 'variable_get_int':
1495
+ const varField = block.getField('VAR');
1496
+ return varField && varField.getVariable() ? varField.getVariable().name : 'unknown_var';
1497
+ case 'int_get':
1498
+ const varFieldIntGet = block.getField('VAR');
1499
+ return varFieldIntGet && varFieldIntGet.getVariable() ? varFieldIntGet.getVariable().name : 'unknown_var';
1500
+ case 'float_get':
1501
+ const varFieldFloatGet = block.getField('VAR');
1502
+ return varFieldFloatGet && varFieldFloatGet.getVariable() ? varFieldFloatGet.getVariable().name : 'unknown_var';
1503
+ case 'ultrasonic_distance':
1504
+ const trig = block.getFieldValue('TRIG');
1505
+ return `distance_${trig}`;
1506
+ default:
1507
+ return '';
1508
+ }
1509
+ }
1510
+
1511
+ function generateCodeForBlock(block) {
1512
+ if (!block) return '';
1513
+ let code = '';
1514
+ while (block) {
1515
+ switch (block.type) {
1516
+ case 'pin_mode':
1517
+ const pin = block.getFieldValue('PIN');
1518
+ const mode = block.getFieldValue('MODE');
1519
+ code += `pinMode(${pin}, ${mode});\n`;
1520
+ break;
1521
+ case 'digital_write':
1522
+ const pinDw = block.getFieldValue('PIN');
1523
+ const value = block.getFieldValue('VALUE');
1524
+ code += `digitalWrite(${pinDw}, ${value});\n`;
1525
+ break;
1526
+ case 'analog_write':
1527
+ const pinAw = block.getFieldValue('PIN');
1528
+ const valueAw = generateValueCode(block.getInputTargetBlock('VALUE')) || '255';
1529
+ code += `analogWrite(${pinAw}, ${valueAw});\n`;
1530
+ break;
1531
+ case 'delay':
1532
+ const time = block.getFieldValue('TIME');
1533
+ code += `delay(${time});\n`;
1534
+ break;
1535
+ case 'delay_microseconds':
1536
+ const timeUs = block.getFieldValue('TIME');
1537
+ code += `delayMicroseconds(${timeUs});\n`;
1538
+ break;
1539
+ case 'delay_microseconds_value':
1540
+ const timeUsValue = generateValueCode(block.getInputTargetBlock('TIME')) || '100';
1541
+ code += `delayMicroseconds(${timeUsValue});\n`;
1542
+ break;
1543
+ case 'delay_value':
1544
+ const timeValue = generateValueCode(block.getInputTargetBlock('TIME')) || '1000';
1545
+ code += `delay(${timeValue});\n`;
1546
+ break;
1547
+ case 'controls_while':
1548
+ const conditionW = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'true';
1549
+ const doCodeW = generateCodeForBlock(block.getInputTargetBlock('DO'));
1550
+ code += `while (${conditionW}) {\n ${doCodeW.replace(/\n/g, '\n ')}\n}\n`;
1551
+ break;
1552
+ case 'controls_if':
1553
+ const conditionIf = generateValueCode(block.getInputTargetBlock('IF0')) || 'true';
1554
+ const doCodeIf = generateCodeForBlock(block.getInputTargetBlock('DO0'));
1555
+ const elseCode = generateCodeForBlock(block.getInputTargetBlock('ELSE'));
1556
+ code += `if (${conditionIf}) {\n ${doCodeIf.replace(/\n/g, '\n ')}\n}`;
1557
+ if (elseCode) code += ` else {\n ${elseCode.replace(/\n/g, '\n ')}\n}`;
1558
+ code += '\n';
1559
+ break;
1560
+ case 'repeat_times':
1561
+ const times = generateValueCode(block.getInputTargetBlock('TIMES')) || '5';
1562
+ const doCode = generateCodeForBlock(block.getInputTargetBlock('DO'));
1563
+ code += `for (int i = 0; i < ${times}; i++) {\n ${doCode.replace(/\n/g, '\n ')}\n}\n`;
1564
+ break;
1565
+ case 'if_condition':
1566
+ const condition = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'true';
1567
+ const ifCode = generateCodeForBlock(block.getInputTargetBlock('DO'));
1568
+ code += `if (${condition}) {\n ${ifCode.replace(/\n/g, '\n ')}\n}\n`;
1569
+ break;
1570
+ case 'wait_until_condition':
1571
+ const waitCondition = generateValueCode(block.getInputTargetBlock('CONDITION')) || 'false';
1572
+ code += `while (!${waitCondition}) {\n delay(10);\n}\n`;
1573
+ break;
1574
+ case 'variable_declare_int':
1575
+ break;
1576
+ case 'variable_set_int':
1577
+ const varField = block.getField('VAR');
1578
+ const varName = varField && varField.getVariable() ? varField.getVariable().name : 'unknown_var';
1579
+ const valueIntNew = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1580
+ code += `${varName} = ${valueIntNew};\n`;
1581
+ break;
1582
+ case 'int_declare':
1583
+ break;
1584
+ case 'int_set':
1585
+ const varFieldInt = block.getField('VAR');
1586
+ const varNameInt = varFieldInt && varFieldInt.getVariable() ? varFieldInt.getVariable().name : 'unknown_var';
1587
+ const valueInt = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1588
+ code += `${varNameInt} = ${valueInt};\n`;
1589
+ break;
1590
+ case 'float_declare':
1591
+ break;
1592
+ case 'float_set':
1593
+ const varFieldFloat = block.getField('VAR');
1594
+ const varNameFloat = varFieldFloat && varFieldFloat.getVariable() ? varFieldFloat.getVariable().name : 'unknown_var';
1595
+ const valueFloat = generateValueCode(block.getInputTargetBlock('VALUE')) || '0.0';
1596
+ code += `${varNameFloat} = ${valueFloat};\n`;
1597
+ break;
1598
+ case 'variable_set_number':
1599
+ const varFieldNum = block.getField('VAR');
1600
+ const varNameNum = varFieldNum && varFieldNum.getVariable() ? varFieldNum.getVariable().name : 'unknown_var';
1601
+ const valueNum = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1602
+ code += `${varNameNum} = ${valueNum};\n`;
1603
+ break;
1604
+ case 'variable_set_string':
1605
+ const varFieldStr = block.getField('VAR');
1606
+ const varNameStr = varFieldStr && varFieldStr.getVariable() ? varFieldStr.getVariable().name : 'unknown_var';
1607
+ let valueStr = generateValueCode(block.getInputTargetBlock('TEXT')) || '""';
1608
+ if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') {
1609
+ valueStr = cleanString(valueStr);
1610
+ }
1611
+ code += `${varNameStr} = ${valueStr};\n`;
1612
+ break;
1613
+ case 'servo_write':
1614
+ const pinServo = block.getFieldValue('PIN');
1615
+ const angle = generateValueCode(block.getInputTargetBlock('ANGLE')) || '90';
1616
+ code += `servo_${pinServo}.write(${angle});\n`;
1617
+ break;
1618
+ case 'ultrasonic_read':
1619
+ const trig = block.getFieldValue('TRIG');
1620
+ const echo = block.getFieldValue('ECHO');
1621
+ code += `digitalWrite(${trig}, LOW);\n`;
1622
+ code += `delayMicroseconds(2);\n`;
1623
+ code += `digitalWrite(${trig}, HIGH);\n`;
1624
+ code += `delayMicroseconds(10);\n`;
1625
+ code += `digitalWrite(${trig}, LOW);\n`;
1626
+ code += `duration_${trig} = pulseIn(${echo}, HIGH);\n`;
1627
+ code += `distance_${trig} = duration_${trig} * 0.034 / 2;\n`;
1628
+ break;
1629
+ case 'lcd_print':
1630
+ const cursorCol = block.getFieldValue('CURSOR_COL');
1631
+ const cursorRow = block.getFieldValue('CURSOR_ROW');
1632
+ let textLcd = generateValueCode(block.getInputTargetBlock('TEXT')) || '"Hello World!!"';
1633
+ if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') {
1634
+ textLcd = cleanString(textLcd);
1635
+ }
1636
+ code += `lcd.setCursor(${cursorCol}, ${cursorRow});\nlcd.print(${textLcd});\n`;
1637
+ break;
1638
+ case 'lcd_print_value':
1639
+ const cursorColVal = block.getFieldValue('CURSOR_COL');
1640
+ const cursorRowVal = block.getFieldValue('CURSOR_ROW');
1641
+ const valueLcd = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1642
+ code += `lcd.setCursor(${cursorColVal}, ${cursorRowVal});\nlcd.print(${valueLcd});\n`;
1643
+ break;
1644
+ case 'lcd_clear':
1645
+ code += `lcd.clear();\n`;
1646
+ break;
1647
+ case 'serial_begin':
1648
+ const baud = block.getFieldValue('BAUD');
1649
+ code += `Serial.begin(${baud});\n`;
1650
+ break;
1651
+ case 'serial_print':
1652
+ let textSerial = generateValueCode(block.getInputTargetBlock('TEXT')) || '""';
1653
+ if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') {
1654
+ textSerial = cleanString(textSerial);
1655
+ }
1656
+ code += `Serial.print(${textSerial});\n`;
1657
+ break;
1658
+ case 'serial_print_value':
1659
+ const valueSerial = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1660
+ code += `Serial.print(${valueSerial});\n`;
1661
+ break;
1662
+ case 'serial_println':
1663
+ let textSerialLn = generateValueCode(block.getInputTargetBlock('TEXT')) || '""';
1664
+ if (block.getInputTargetBlock('TEXT')?.type !== 'serial_read_string') {
1665
+ textSerialLn = cleanString(textSerialLn);
1666
+ }
1667
+ code += `Serial.println(${textSerialLn});\n`;
1668
+ break;
1669
+ case 'serial_println_value':
1670
+ const valueSerialLn = generateValueCode(block.getInputTargetBlock('VALUE')) || '0';
1671
+ code += `Serial.println(${valueSerialLn});\n`;
1672
+ break;
1673
+ case 'custom_code':
1674
+ const customCode = block.getFieldValue('CODE');
1675
+ code += `${customCode}\n`;
1676
+ break;
1677
+ case 'seven_segment_display':
1678
+ const pinA = block.getFieldValue('PIN_A');
1679
+ const pinB = block.getFieldValue('PIN_B');
1680
+ const pinC = block.getFieldValue('PIN_C');
1681
+ const pinD = block.getFieldValue('PIN_D');
1682
+ const pinE = block.getFieldValue('PIN_E');
1683
+ const pinF = block.getFieldValue('PIN_F');
1684
+ const pinG = block.getFieldValue('PIN_G');
1685
+ const number = generateValueCode(block.getInputTargetBlock('NUMBER')) || '0';
1686
+ code += `if (${number} == -1) {\n`;
1687
+ code += ` digitalWrite(${pinA}, LOW);\n`;
1688
+ code += ` digitalWrite(${pinB}, LOW);\n`;
1689
+ code += ` digitalWrite(${pinC}, LOW);\n`;
1690
+ code += ` digitalWrite(${pinD}, LOW);\n`;
1691
+ code += ` digitalWrite(${pinE}, LOW);\n`;
1692
+ code += ` digitalWrite(${pinF}, LOW);\n`;
1693
+ code += ` digitalWrite(${pinG}, LOW);\n`;
1694
+ code += `} else {\n`;
1695
+ code += ` int digit = constrain(${number}, 0, 9);\n`;
1696
+ code += ` digitalWrite(${pinA}, ${segmentPatterns[0][0] ? 'HIGH' : 'LOW'});\n`;
1697
+ code += ` digitalWrite(${pinB}, ${segmentPatterns[0][1] ? 'HIGH' : 'LOW'});\n`;
1698
+ code += ` digitalWrite(${pinC}, ${segmentPatterns[0][2] ? 'HIGH' : 'LOW'});\n`;
1699
+ code += ` digitalWrite(${pinD}, ${segmentPatterns[0][3] ? 'HIGH' : 'LOW'});\n`;
1700
+ code += ` digitalWrite(${pinE}, ${segmentPatterns[0][4] ? 'HIGH' : 'LOW'});\n`;
1701
+ code += ` digitalWrite(${pinF}, ${segmentPatterns[0][5] ? 'HIGH' : 'LOW'});\n`;
1702
+ code += ` digitalWrite(${pinG}, ${segmentPatterns[0][6] ? 'HIGH' : 'LOW'});\n`;
1703
+ 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`;
1704
+ 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`;
1705
+ 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`;
1706
+ 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`;
1707
+ 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`;
1708
+ 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`;
1709
+ 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`;
1710
+ 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`;
1711
+ 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`;
1712
+ code += `}\n`;
1713
+ break;
1714
+ case 'tone':
1715
+ const tonePin = block.getFieldValue('PIN');
1716
+ const frequency = generateValueCode(block.getInputTargetBlock('FREQUENCY')) || '440';
1717
+ code += `tone(${tonePin}, ${frequency});\n`;
1718
+ break;
1719
+ case 'noTone':
1720
+ const noTonePin = block.getFieldValue('PIN');
1721
+ code += `noTone(${noTonePin});\n`;
1722
+ break;
1723
+ }
1724
+ block = block.getNextBlock();
1725
+ }
1726
+ return code;
1727
+ }
1728
+
1729
+ workspace.addChangeListener(function (event) {
1730
+ const arduinoCode = generateArduinoCode();
1731
+ document.getElementById('generated-code').textContent = arduinoCode;
1732
+ if (event.type === Blockly.Events.BLOCK_CREATE ||
1733
+ event.type === Blockly.Events.BLOCK_DELETE ||
1734
+ event.type === Blockly.Events.BLOCK_MOVE ||
1735
+ event.type === Blockly.Events.BLOCK_CHANGE) {
1736
+ saveWorkspaceToUrl();
1737
+ }
1738
+ });
1739
+
1740
+ document.getElementById('clear-btn').addEventListener('click', function () {
1741
+ workspace.clear();
1742
+ document.getElementById('generated-code').textContent = '// 生成されたArduinoコードがここに表示されます';
1743
+ const url = new URL(window.location);
1744
+ url.searchParams.delete('blocks');
1745
+ history.pushState({}, '', url);
1746
+ });
1747
+
1748
+ document.getElementById('save-btn').addEventListener('click', function () {
1749
+ const url = window.location.href;
1750
+ navigator.clipboard.writeText(url).then(() => {
1751
+ alert('URLがクリップボードにコピーされました!');
1752
+ }).catch(err => {
1753
+ console.error('URLのコピーに失敗しました:', err);
1754
+ });
1755
+ });
1756
+
1757
+ document.getElementById('download-btn').addEventListener('click', function () {
1758
+ const code = document.getElementById('generated-code').textContent;
1759
+ const now = new Date();
1760
+ const timestamp = now.getFullYear() +
1761
+ ('0' + (now.getMonth() + 1)).slice(-2) +
1762
+ ('0' + now.getDate()).slice(-2) +
1763
+ ('0' + now.getHours()).slice(-2) +
1764
+ ('0' + now.getMinutes()).slice(-2);
1765
+ const filename = `${timestamp}.ino`;
1766
+ const blob = new Blob([code], { type: 'text/x-arduino' });
1767
+ const url = window.URL.createObjectURL(blob);
1768
+ const a = document.createElement('a');
1769
+ a.href = url;
1770
+ a.download = filename;
1771
+ document.body.appendChild(a);
1772
+ a.click();
1773
+ document.body.removeChild(a);
1774
+ window.URL.revokeObjectURL(url);
1775
+ });
1776
+
1777
+ document.getElementById('print-btn').addEventListener('click', function () {
1778
+ html2canvas(document.getElementById('block-area')).then(canvas => {
1779
+ const image = canvas.toDataURL('image/png');
1780
+ const printWindow = window.open('');
1781
+ printWindow.document.write('<img src="' + image + '" onload="window.print();window.close()" />');
1782
+ printWindow.document.close();
1783
+ });
1784
+ });
1785
+
1786
+ // シリアル通信ボタンのイベントリスナー
1787
+ document.getElementById('serial-btn').addEventListener('click', function () {
1788
+ const modal = document.getElementById('serial-modal');
1789
+ const iframe = document.getElementById('serial-iframe');
1790
+ iframe.src = 'pv17-3.html'; // index2.htmlを読み込む
1791
+ modal.style.display = 'block'; // モーダルを表示
1792
+ });
1793
+
1794
+ // 閉じるボタンのイベントリスナー
1795
+ document.getElementById('close-modal').addEventListener('click', function () {
1796
+ const modal = document.getElementById('serial-modal');
1797
+ const iframe = document.getElementById('serial-iframe');
1798
+ modal.style.display = 'none'; // モーダルを非表示
1799
+ iframe.src = ''; // iframeの内容をリセット
1800
+ });
1801
+
1802
+ document.getElementById('exit-btn').addEventListener('click', function () {
1803
+ window.location.href = 'https://huggingface.co/ek15072809';
1804
+ });
1805
+
1806
+ loadWorkspaceFromUrl();
1807
+ </script>
1808
+ </body>
1809
+ </html>