diff --git a/images/hardware/neo.png b/images/hardware/neo.png new file mode 100644 index 0000000000..0ee93984a3 Binary files /dev/null and b/images/hardware/neo.png differ diff --git a/images/hw/neo.png b/images/hw/neo.png new file mode 100644 index 0000000000..0ee93984a3 Binary files /dev/null and b/images/hw/neo.png differ diff --git a/images/hw_lite/chocolite.png b/images/hw_lite/chocolite.png new file mode 100644 index 0000000000..0b75a9b486 Binary files /dev/null and b/images/hw_lite/chocolite.png differ diff --git a/images/hw_lite/neo_lite.png b/images/hw_lite/neo_lite.png new file mode 100644 index 0000000000..0ee93984a3 Binary files /dev/null and b/images/hw_lite/neo_lite.png differ diff --git a/src/playground/blocks/hardware/block_0uboard.js b/src/playground/blocks/hardware/block_0uboard.js index 9cbaa88e62..cf6d7c1fc1 100644 --- a/src/playground/blocks/hardware/block_0uboard.js +++ b/src/playground/blocks/hardware/block_0uboard.js @@ -37,7 +37,7 @@ Entry.pyocoding = { OLED: 241, COM: 242, NEOPIXELCOLOR: 243, - + DOTMATRIX: 245, }, duration: { TIME_1ms: 1, @@ -103,6 +103,10 @@ Entry.pyocoding.setLanguage = function() { pyocoding_neopixel_all_led: '네오픽셀 %1 번에 LED R: %2 , G: %3 , B: %4 색을 밝기 %5 으로 켜기', pyocoding_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', pyocoding_set_tone: '디지털 %1 번 핀을 %2 음으로 %3 옥타브로 %4 만큼 연주하기 %5', + pyocoding_change_4095to255_value: '%1 값 %2을 %3로 변환하기', + pyocoding_change_analog_to_temperature_tc_value: '아날로그 온도 변환 %1', + pyocoding_get_touch_value : '터치 %1 센서값', + pyocoding_dotmatrix : '도트매트릭스 %1 번 배열에 %2 을 그리기', }, }, en: { @@ -137,6 +141,10 @@ Entry.pyocoding.setLanguage = function() { pyocoding_neopixel_all_led: '디지털 %1 번 핀에 연결된 %2 번째 네오픽셀 LED R: %3 , G: %4 , B: %5 색으로 켜기', pyocoding_digital_pwm: 'Digital %1 Pin %2 %3', pyocoding_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', + pyocoding_change_4095to255_value: 'Analog 4095to255 %1', + pyocoding_change_analog_to_temperature_tc_value: 'Analog to Tc %1', + pyocoding_get_touch_value : 'touch %1 value', + pyocoding_dotmatrix : '도트매트릭스 %1 번 배열에 %2 을 그리기', }, }, }; @@ -158,6 +166,10 @@ Entry.pyocoding.blockMenuBlocks = [ 'pyocoding_neopixel_set', 'pyocoding_neopixel_led', 'pyocoding_neopixel_all_led', + 'pyocoding_change_4095to255_value', + 'pyocoding_change_analog_to_temperature_tc_value', + 'pyocoding_get_touch_value', + 'pyocoding_dotmatrix', ]; @@ -295,11 +307,151 @@ Entry.pyocoding.getBlocks = function() { func: function (sprite, script) { var port = script.getValue("PORT", script); var ANALOG = Entry.hw.portData.ANALOG; + //console.log(port,ANALOG) if (port[0] === "A") port = port.substring(1) return ANALOG ? ANALOG[port] || 0 : 0; }, }, + pyocoding_get_touch_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + events: {}, + params: [ + { + "type": "Dropdown", + "options": [ + [ "A3", "3" ], + //[ "A5", "5" ], + ], + "value": "3", + "fontSize": 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + def: { + params: [ null ], + "type": "pyocoding_get_touch_value" + }, + isNotFor: [ '0uboard' ], + class: "SENSOR", + paramsKeyMap: { + "PORT": 0, + }, + func: function (sprite, script) { + var port = script.getValue("PORT", script); + var ANALOG = Entry.hw.portData.ANALOG; + console.log(port,ANALOG) + if (port[0] === "A") + port = port.substring(1) + return ANALOG ? ANALOG[5] || 0 : 0; + }, + }, + pyocoding_change_4095to255_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + events: {}, + params: [ + { + "type": "Block", + "accept": "string" + }, + { + "type": "Block", + "accept": "string" + }, + { + "type": "Block", + "accept": "string" + }, + ], + def: { + params: [ + { + "type": "text", + "params": [ "0" ] + }, + { + "type": "text", + "params": [ "4095" ] + }, + { + "type": "text", + "params": [ "255" ] + }, + ], + "type": "pyocoding_change_4095to255_value" + }, + isNotFor: [ '0uboard' ], + class: "ext", + paramsKeyMap: { + "VALUE": 0, + "VALUE2": 1, + "VALUE3": 2, + }, + func: function (sprite, script) { + var value = script.getNumberValue("VALUE"); + var value2 = script.getNumberValue("VALUE2"); + var value3 = script.getNumberValue("VALUE3"); + console.log(value,value2,value3); + var dividedValue = Math.floor(value / (value2 / value3)); + + return dividedValue; + }, + }, + pyocoding_change_analog_to_temperature_tc_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + events: {}, + params: [ + { + "type": "Block", + "accept": "string" + }, + ], + def: { + params: [ + { + "type": "text", + "params": [ "0" ] + }, + null + ], + "type": "pyocoding_change_analog_to_temperature_tc_value" + }, + isNotFor: [ '0uboard' ], + class: "ext", + paramsKeyMap: { + "VALUE": 0, + }, + func: function (sprite, script) { + + var R1 = 10000; + var logR2, R2, T, Tc, Tf; + var c1 = 1.106836861e-03, c2 = 2.384641754e-04, c3 = 0.6507394466e-07; + + var Vo = script.getNumberValue("VALUE"); + + R2 = R1 * ((4095.0 / Vo) - 1.0); + logR2 = Math.log(R2); + T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); + Tc = T - 273.15; //섭씨 + //Tf = (Tc * 9.0)/ 5.0 + 32.0; //화씨 + + // Print the result to the console + //console.log("vo:",Vo,"Tc:",Tc); + + // You can return the value in Fahrenheit as well + return Tc; + }, + }, pyocoding_get_port_number: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -1388,6 +1540,147 @@ Entry.pyocoding.getBlocks = function() { syntax: { }, }, + pyocoding_dotmatrix: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + "type": "Dropdown", + "options": [ + ["0","0"], + ["1","1"], + ["2","2"], + ["3","3"], + ["4","4"], + ["5","5"], + ["6","6"], + ["7","7"], + ], + "value":"0", + "fontSize":11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['00001111'], + }, + { + type: 'number', + params: ['255'], + }, + { + type: 'number', + params: ['255'], + }, + { + type: 'number', + params: ['100'], + }, + null, + ], + type: 'pyocoding_dotmatrix', + }, + paramsKeyMap: { + INDEX : 0, + RED: 1, + GREEN: 2, + BLUE: 3, + BRIG: 4, + }, + class: 'neopixel', + isNotFor: ['0uboard'], + func(sprite, script) { + var port = script.getNumberValue("INDEX"); + var red = script.getNumberValue("RED"); + var green = script.getNumberValue("GREEN"); + var blue = script.getNumberValue("BLUE"); + var brig = script.getNumberValue("BRIG"); + var mode = 3; + + let str = parseInt(String(red), 2); + red = str; + + if(red > 255) red=255; + console.log(red); + + + if (!script.isStart) + { + + if(!Entry.hw.sendQueue['SET']) { + Entry.hw.sendQueue['SET'] = {}; + } + var duration = Entry.Orange.duration.TIME_10ms; + script.isStart = true; + script.timeFlag = 1; + + Entry.hw.sendQueue['SET'][port] = { + type: Entry.pyocoding.sensorTypes.DOTMATRIX, + data: + { + index : port, + mode: mode, + red: red, + green: green, + blue: blue, + brig: brig, + }, + time: new Date().getTime() + }; + setTimeout(function() { + script.timeFlag = 0; + }, duration ); + return script; + } + else if (script.timeFlag == 1) + { + return script; + } + else + { + delete script.timeFlag; + delete script.isStart; + + Entry.engine.isContinue = false; + return script.callReturn(); + } + }, + syntax: { + }, + }, } //return }; //function diff --git a/src/playground/blocks/hardware/block_aibot.js b/src/playground/blocks/hardware/block_aibot.js index bd8d4dccff..05e45ea771 100644 --- a/src/playground/blocks/hardware/block_aibot.js +++ b/src/playground/blocks/hardware/block_aibot.js @@ -177,8 +177,10 @@ Entry.aibot.setLanguage = function() { aibot_set_port_out: '디지털출력 %1번 %2 %3', aibot_buzzer_play: '%1 효과음 재생하기 %2', aibot_set_servo_speed: '제어속도를 %1로 정하기 %2', + aibot_set_servo_angle_single_numtype: '모듈 %1을 %2각도로 제어%3', aibot_set_servo_angle_single: '모듈 %1을 %2각도로 제어%3', aibot_set_servo_angle_123: '모듈 1%1, 2%2, 3%3 각도로 제어%4', + aibot_set_servo_angle_1234: '모듈 1%1, 2%2, 3%3, 4%4 각도로 제어%5', aibot_set_servo_angle_56: '모듈 5%1, 6%2 각도로 제어%3', aibot_set_servo_angle_123456: '모듈 1%1, 2%2, 3%3, 4%4, 5%5, 6%6 각도로 제어%7', aibot_set_servo_go_home: '모든 모듈을 기본위치로 제어하기(원점복귀) %1', @@ -186,8 +188,10 @@ Entry.aibot.setLanguage = function() { //aibot_set_servo_home_pos_angle: '%1번 모듈의 기본위치 각도를 %2도로 설정하기%3', aibot_set_servo_home_pos_current: '%1번 모듈의 90도 위치를 현재의 위치로 정하기%2', aibot_set_remote_servo_speed: '원격의 제어속도를 %1로 정하기 %2', - aibot_set_remote_servo_angle_single: '원격모듈 %1을 %2각도로 제어%3', + aibot_set_remote_servo_angle_single: '원격모듈 %1을 %2각도로 제어%3', + aibot_set_remote_servo_angle_single_numtype: '원격모듈 %1을 %2각도로 제어%3', aibot_set_remote_servo_angle_123: '원격모듈 1%1, 2%2, 3%3 각도로 제어%4', + aibot_set_remote_servo_angle_1234: '원격모듈 1%1, 2%2, 3%3, 4%4 각도로 제어%5', aibot_set_remote_servo_angle_56: '원격모듈 5%1, 6%2 각도로 제어%3', aibot_set_remote_servo_angle_123456: '원격모듈 1%1, 2%2, 3%3, 4%4, 5%5, 6%6 각도로 제어%7', aibot_set_remote_servo_go_home: '원격의 모든 모듈을 기본위치로 제어하기(원점복귀) %1', @@ -216,8 +220,10 @@ Entry.aibot.setLanguage = function() { aibot_set_port_out: 'PORT %1 OUT %2 %3', aibot_buzzer_play: '%1 play melody %2', aibot_set_servo_speed: 'Control Speed %1 %2', + aibot_set_servo_angle_single_numtype: '%1 SERVO %2 DEGREE %3', aibot_set_servo_angle_single: '%1 SERVO %2 DEGREE %3', - aibot_set_servo_angle_123: 'Module control degree 1%1, 2%2 3%3 %4', + aibot_set_servo_angle_123: 'Module control degree 1%1, 2%2 3%3 %4', + aibot_set_servo_angle_1234: 'Module control degree 1%1, 2%2, 3%3, 4%4 %5', aibot_set_servo_angle_56: 'Module control degree 5%1, 6%2 %3', aibot_set_servo_angle_123456: 'Module control degree 1%1, 2%2, 3%3, 4%4, 5%5, 6%6 %7', aibot_set_servo_go_home: 'Module Home Position %1', @@ -225,8 +231,10 @@ Entry.aibot.setLanguage = function() { //aibot_set_servo_home_pos_angle: 'Servo %1 Set Home Position to %2degree %3', aibot_set_servo_home_pos_current: 'Servo %1 Set Home Position to current %2', aibot_set_remote_servo_speed: 'Remote Control Speed %1 %2', + aibot_set_remote_servo_angle_single_numtype: 'Remote %1 Module %2 DEGREE %3', aibot_set_remote_servo_angle_single: 'Remote %1 Module %2 DEGREE %3', - aibot_set_remote_servo_angle_123: 'Remote Module control degree 1%1, 2%2 3%3 %4', + aibot_set_remote_servo_angle_123: 'Remote Module control degree 1%1, 2%2 3%3 %4', + aibot_set_remote_servo_angle_1234: 'Remote Module control degree 1%1, 2%2, 3%3, 4%4 %5', aibot_set_remote_servo_angle_56: 'Remote Module control degree 5%1, 6%2 %3', aibot_set_remote_servo_angle_123456: 'Remote Module control degree 1%1, 2%2, 3%3, 4%4, 5%5, 6%6 %7', aibot_set_remote_servo_go_home: 'Remote Module Home Position %1', @@ -257,8 +265,10 @@ Entry.aibot.blockMenuBlocks = [ 'aibot_set_port_out', 'aibot_buzzer_play', 'aibot_set_servo_speed', + 'aibot_set_servo_angle_single_numtype', 'aibot_set_servo_angle_single', 'aibot_set_servo_angle_123', + 'aibot_set_servo_angle_1234', 'aibot_set_servo_angle_56', 'aibot_set_servo_angle_123456', 'aibot_set_servo_go_home', @@ -266,8 +276,10 @@ Entry.aibot.blockMenuBlocks = [ 'aibot_set_servo_home_pos_current', 'aibot_set_set_offset_zero', 'aibot_set_remote_servo_speed', + 'aibot_set_remote_servo_angle_single_numtype', 'aibot_set_remote_servo_angle_single', 'aibot_set_remote_servo_angle_123', + 'aibot_set_remote_servo_angle_1234', 'aibot_set_remote_servo_angle_56', 'aibot_set_remote_servo_angle_123456', 'aibot_set_remote_servo_go_home', @@ -674,6 +686,88 @@ Entry.aibot.getBlocks = function() { } }, }, + aibot_set_servo_angle_single_numtype: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1,90], + type: 'aibot_set_servo_angle_single_numtype', + }, + paramsKeyMap: { + SERVO: 0, + ANGLE: 1, + }, + class: 'aibot', + isNotFor: ['aibot'], + func: function(sprite, script) { + if(!script.isStart) + { + script.isStart = true; + script.timeFlag = 1; + var timer = setTimeout(function() { + script.timeFlag = 0; + Entry.aibot.removeTimeout(timer); + }, Entry.aibot.delayTime); + Entry.aibot.timeouts.push(timer); + return script; + } + else if(script.timeFlag == 1) + { + return script; + } + else + { + var sq = Entry.hw.sendQueue; + var Servo1=0;var Servo2=0;var Servo3=0; + var Servo4=0;var Servo5=0;var Servo6=0; + var Servo = script.getNumberValue('SERVO', script); + var Angle = script.getNumberValue('ANGLE', script); + + if(Angle<0)Angle = 0;if(Angle>180)Angle = 180;Angle = Angle*10 + 700; + + if(Servo==1)Servo1 = Angle; + else if(Servo==2)Servo2 = Angle; + else if(Servo==3)Servo3 = Angle; + else if(Servo==4)Servo4 = Angle; + else if(Servo==5)Servo5 = Angle; + else if(Servo==6)Servo6 = Angle; + + var Remote = 1; + sq['SEND'] = {}; + sq['SEND'][Entry.aibot.array.SERVO_CONTROL] = { + remote: Remote, + servo1: Servo1, + servo2: Servo2, + servo3: Servo3, + servo4: Servo4, + servo5: Servo5, + servo6: Servo6, + Time: new Date().getTime(), + }; + return script.callReturn(); + } + }, + }, aibot_set_servo_angle_single: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -764,6 +858,95 @@ Entry.aibot.getBlocks = function() { } }, }, + aibot_set_remote_servo_angle_1234: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['90','90','90','90'], + type: 'aibot_set_remote_servo_angle_1234', + }, + paramsKeyMap: { + SERVO1: 0, + SERVO2: 1, + SERVO3: 2, + SERVO4: 3, + }, + class: 'aibot_remote', + isNotFor: ['aibot'], + func: function(sprite, script) { + if(!script.isStart) + { + script.isStart = true; + script.timeFlag = 1; + var timer = setTimeout(function() { + script.timeFlag = 0; + Entry.aibot.removeTimeout(timer); + }, Entry.aibot.delayTime); + Entry.aibot.timeouts.push(timer); + return script; + } + else if(script.timeFlag == 1) + { + return script; + } + else + { + var sq = Entry.hw.sendQueue; + var Servo1=script.getNumberValue('SERVO1', script); + var Servo2=script.getNumberValue('SERVO2', script); + var Servo3=script.getNumberValue('SERVO3', script); + var Servo4=script.getNumberValue('SERVO4', script); + if(Servo1<0)Servo1 = 0;if(Servo1>180)Servo1 = 180;Servo1 = Servo1*10 + 700; + if(Servo2<0)Servo2 = 0;if(Servo2>180)Servo2 = 180;Servo2 = Servo2*10 + 700; + if(Servo3<0)Servo3 = 0;if(Servo3>180)Servo3 = 180;Servo3 = Servo3*10 + 700; + if(Servo4<0)Servo4 = 0;if(Servo4>180)Servo4 = 180;Servo4 = Servo4*10 + 700; + + var Remote = 2; + sq['SEND'] = {}; + sq['SEND'][Entry.aibot.array.SERVO_CONTROL] = { + remote: Remote, + servo1: Servo1, + servo2: Servo2, + servo3: Servo3, + servo4: Servo4, + servo5: 0, + servo6: 0, + Time: new Date().getTime(), + }; + return script.callReturn(); + } + }, + }, aibot_set_remote_servo_angle_123456: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -974,6 +1157,95 @@ Entry.aibot.getBlocks = function() { } }, }, + aibot_set_servo_angle_1234: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['90','90','90','90'], + type: 'aibot_set_servo_angle_1234', + }, + paramsKeyMap: { + SERVO1: 0, + SERVO2: 1, + SERVO3: 2, + SERVO4: 3, + }, + class: 'aibot', + isNotFor: ['aibot'], + func: function(sprite, script) { + if(!script.isStart) + { + script.isStart = true; + script.timeFlag = 1; + var timer = setTimeout(function() { + script.timeFlag = 0; + Entry.aibot.removeTimeout(timer); + }, Entry.aibot.delayTime); + Entry.aibot.timeouts.push(timer); + return script; + } + else if(script.timeFlag == 1) + { + return script; + } + else + { + var sq = Entry.hw.sendQueue; + var Servo1=script.getNumberValue('SERVO1', script); + var Servo2=script.getNumberValue('SERVO2', script); + var Servo3=script.getNumberValue('SERVO3', script); + var Servo4=script.getNumberValue('SERVO4', script); + if(Servo1<0)Servo1 = 0;if(Servo1>180)Servo1 = 180;Servo1 = Servo1*10 + 700; + if(Servo2<0)Servo2 = 0;if(Servo2>180)Servo2 = 180;Servo2 = Servo2*10 + 700; + if(Servo3<0)Servo3 = 0;if(Servo3>180)Servo3 = 180;Servo3 = Servo3*10 + 700; + if(Servo4<0)Servo4 = 0;if(Servo4>180)Servo4 = 180;Servo4 = Servo4*10 + 700; + + var Remote = 1; + sq['SEND'] = {}; + sq['SEND'][Entry.aibot.array.SERVO_CONTROL] = { + remote: Remote, + servo1: Servo1, + servo2: Servo2, + servo3: Servo3, + servo4: Servo4, + servo5: 0, + servo6: 0, + Time: new Date().getTime(), + }; + return script.callReturn(); + } + }, + }, aibot_set_servo_angle_123: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -1196,6 +1468,88 @@ Entry.aibot.getBlocks = function() { } }, }, + aibot_set_remote_servo_angle_single_numtype: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1,90], + type: 'aibot_set_remote_servo_angle_single_numtype', + }, + paramsKeyMap: { + SERVO: 0, + ANGLE: 1, + }, + class: 'aibot_remote', + isNotFor: ['aibot'], + func: function(sprite, script) { + if(!script.isStart) + { + script.isStart = true; + script.timeFlag = 1; + var timer = setTimeout(function() { + script.timeFlag = 0; + Entry.aibot.removeTimeout(timer); + }, Entry.aibot.delayTime); + Entry.aibot.timeouts.push(timer); + return script; + } + else if(script.timeFlag == 1) + { + return script; + } + else + { + var sq = Entry.hw.sendQueue; + var Servo1=0,Servo2=0,Servo3=0; + var Servo4=0,Servo5=0,Servo6=0; + var Servo = script.getNumberValue('SERVO', script); + var Angle = script.getNumberValue('ANGLE', script); + + if(Angle<0)Angle = 0;if(Angle>180)Angle = 180;Angle = Angle*10 + 700; + + if(Servo==1)Servo1 = Angle; + else if(Servo==2)Servo2 = Angle; + else if(Servo==3)Servo3 = Angle; + else if(Servo==4)Servo4 = Angle; + else if(Servo==5)Servo5 = Angle; + else if(Servo==6)Servo6 = Angle; + + var Remote = 2; + sq['SEND'] = {}; + sq['SEND'][Entry.aibot.array.SERVO_CONTROL] = { + remote: Remote, + servo1: Servo1, + servo2: Servo2, + servo3: Servo3, + servo4: Servo4, + servo5: Servo5, + servo6: Servo6, + Time: new Date().getTime(), + }; + return script.callReturn(); + } + }, + }, aibot_set_remote_servo_angle_single: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, diff --git a/src/playground/blocks/hardware/block_coalaboard.js b/src/playground/blocks/hardware/block_coalaboard.js index b29e9ad34d..988edcd06b 100644 --- a/src/playground/blocks/hardware/block_coalaboard.js +++ b/src/playground/blocks/hardware/block_coalaboard.js @@ -27,9 +27,9 @@ Entry.Coalaboard = { LEDB: 16, }, INEQ_SIGN: [ - ["<", "<"], - [">", ">"], - ["=", "="] + ['<', '<'], + ['>', '>'], + ['=', '='], ], sensorList: function() { var list = []; @@ -80,12 +80,13 @@ Entry.Coalaboard = { setZero: function() { let sq = Entry.hw.sendQueue; for (let port in Entry.Coalaboard.PORT_MAP) { - let portData = Entry.hw.portData[port]; - if( portData != null ) { - if( portData.type == Entry.Coalaboard.SENSOR_MAP[18] ) { // DC모터 인 경우, 129로 세팅하여 바로 멈추기 + let portData = Entry.hw.portData[port]; + if (portData != null) { + if (portData.type == Entry.Coalaboard.SENSOR_MAP[18]) { + // DC모터 인 경우, 129로 세팅하여 바로 멈추기 sq[port] = 129; } else { - sq[port] = 0; + sq[port] = 0; } } else { sq[port] = 0; @@ -105,81 +106,85 @@ Entry.Coalaboard = { servoMinValue: 1, dcMaxValue: 100, dcMinValue: -100, - monitorTemplate: { + /** + * 콜백 함수. 계속해서 센서 데이터를 받는다. + * @param {*} pd + */ + afterReceive(pd) { + for (let i = 1; i < 5; i++) { + // 오직 센서만 받기 + let obj = pd[i]; // ex) null or { type: "touch", value: 1023 } + if (obj != null) { + if (obj.type == 'touch' && obj.value == 0) { + Entry.engine.fireEvent('coalaboardButtonEventReceive'); + } + Entry.engine.fireEvent('coalaboardSensorGetValueEventReceive'); + } + } + }, + calculateDCMotorValue: function(value) { + let val = 0; + if (value > 0) { + val = Math.floor(value * 0.8 + 16); + } else if (value < 0) { + val = Math.ceil(value * 0.8 - 19); + } else { + val = 0; + } + // DC_MOTOR_ADJUSTMENT 128 + val = 128 + val; + if (val == 128) { + val = 129; + } + return val; + }, +}; + +Entry.Coalaboard.monitorTemplate = function() { + return { keys: ['value'], imgPath: 'hw/coalaboard.png', width: 400, height: 400, listPorts: { - 'UserInput': { + UserInput: { name: Lang.Blocks.COALABOARD_UserInput, type: 'input', pos: { x: 0, y: 0 }, }, - 'potentiometer': { + potentiometer: { name: Lang.Blocks.COALABOARD_potentiometer, type: 'input', pos: { x: 0, y: 0 }, }, - 'MIC': { + MIC: { name: Lang.Blocks.COALABOARD_MIC, type: 'input', pos: { x: 0, y: 0 }, }, - 'IR': { + IR: { name: Lang.Blocks.COALABOARD_IR, type: 'input', pos: { x: 0, y: 0 }, }, - 'temperature': { + temperature: { name: Lang.Blocks.COALABOARD_temperature, type: 'input', pos: { x: 0, y: 0 }, }, - 'light': { + light: { name: Lang.Blocks.COALABOARD_light, type: 'input', pos: { x: 0, y: 0 }, }, - 'touch': { + touch: { name: Lang.Blocks.COALABOARD_touch, type: 'input', pos: { x: 0, y: 0 }, }, }, mode: 'both', - }, - /** - * 콜백 함수. 계속해서 센서 데이터를 받는다. - * @param {*} pd - */ - afterReceive(pd) { - for( let i = 1; i < 5; i++ ) { // 오직 센서만 받기 - let obj = pd[ i ]; // ex) null or { type: "touch", value: 1023 } - if( obj != null ) { - if( obj.type == 'touch' && obj.value == 0 ) { - Entry.engine.fireEvent('coalaboardButtonEventReceive'); - } - Entry.engine.fireEvent('coalaboardSensorGetValueEventReceive'); - } - } - }, - calculateDCMotorValue: function( value ) { - let val = 0; - if ( value > 0 ) { - val = Math.floor( ( value * 0.8 ) + 16 ); - } else if ( value < 0 ) { - val = Math.ceil( ( value * 0.8 ) - 19 ); - } else { - val = 0; - } - // DC_MOTOR_ADJUSTMENT 128 - val = 128 + val; - if ( val == 128 ) { - val = 129; - } - return val; - } + }; }; Entry.Coalaboard.blockMenuBlocks = [ @@ -193,7 +198,7 @@ Entry.Coalaboard.blockMenuBlocks = [ 'coalaboard_turn_on_color_led_by_picker', 'coalaboard_turn_on_color_led_by_value', 'coalaboard_turn_off_color_led', - 'coalaboard_buzzer', + 'coalaboard_buzzer', 'coalaboard_servomotor_angle', 'coalaboard_dc_direction_speed', 'coalaboard_dc_speed', @@ -201,9 +206,8 @@ Entry.Coalaboard.blockMenuBlocks = [ ]; Entry.Coalaboard.getBlocks = function() { - let options_COALABOARD_button2 = - [ - [Lang.Blocks.COALABOARD_button_pressed, 'pressed'], + let options_COALABOARD_button2 = [ + [Lang.Blocks.COALABOARD_button_pressed, 'pressed'], [Lang.Blocks.COALABOARD_button_released, 'released'], ]; return { @@ -221,9 +225,9 @@ Entry.Coalaboard.getBlocks = function() { size: 12, position: { x: 0, - y: 0 - } - }, + y: 0, + }, + }, { type: 'DropdownDynamic', value: null, @@ -240,17 +244,17 @@ Entry.Coalaboard.getBlocks = function() { }, paramsKeyMap: { DUMMY: 0, - PORT: 1 + PORT: 1, }, class: 'event', isNotFor: ['coalaboard'], event: 'coalaboardButtonEventReceive', func: function(sprite, script) { - let selectedSensor = script.values[ 1 ]; + let selectedSensor = script.values[1]; let port = script.getStringField('PORT'); let type = Entry.hw.portData[port].type; - let val = Entry.hw.portData[port].value; // 0이면 누름, 1023이면 누르지 않음 - if( selectedSensor == port ) { + let val = Entry.hw.portData[port].value; // 0이면 누름, 1023이면 누르지 않음 + if (selectedSensor == port) { if (val == 0) { return script.callReturn(); } else { @@ -261,7 +265,7 @@ Entry.Coalaboard.getBlocks = function() { } }, syntax: { js: [], py: ['Coalaboard.when_button_pressed(%2, %3)'] }, - }, + }, coalaboard_when_sensor_get_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -275,9 +279,9 @@ Entry.Coalaboard.getBlocks = function() { size: 12, position: { x: 0, - y: 0 - } - }, + y: 0, + }, + }, { type: 'DropdownDynamic', value: null, @@ -308,7 +312,7 @@ Entry.Coalaboard.getBlocks = function() { { type: 'text', params: ['100'], - } + }, ], type: 'coalaboard_when_sensor_get_value', }, @@ -316,29 +320,29 @@ Entry.Coalaboard.getBlocks = function() { DUMMY: 0, PORT: 1, INEQ_SIGN: 2, - VALUE: 3 + VALUE: 3, }, class: 'event', isNotFor: ['coalaboard'], event: 'coalaboardSensorGetValueEventReceive', func: function(sprite, script) { - let selectedPort = script.values[ 1 ]; - let ineqSign = script.values[ 2 ]; - let value = script.values[ 3 ]; - let port = script.getStringField('PORT'); - let val = Entry.hw.portData[port].value; - if( selectedPort == port && ineqSign == '<' && val < value ) { + let selectedPort = script.values[1]; + let ineqSign = script.values[2]; + let value = script.values[3]; + let port = script.getStringField('PORT'); + let val = Entry.hw.portData[port].value; + if (selectedPort == port && ineqSign == '<' && val < value) { return script.callReturn(); - } else if( selectedPort == port && ineqSign == '>' && val > value ) { + } else if (selectedPort == port && ineqSign == '>' && val > value) { return script.callReturn(); - } else if( selectedPort == port && ineqSign == '=' && val == value ) { + } else if (selectedPort == port && ineqSign == '=' && val == value) { return script.callReturn(); } else { return this.die(); } }, syntax: { js: [], py: ['Coalaboard.when_sensor_get_value(%2,%3,%4)'] }, - }, + }, coalaboard_sensor_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -484,7 +488,7 @@ Entry.Coalaboard.getBlocks = function() { fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, - }, + }, ], events: {}, def: { @@ -493,21 +497,21 @@ Entry.Coalaboard.getBlocks = function() { }, paramsKeyMap: { PORT: 0, - PRESSED: 1 + PRESSED: 1, }, class: 'button', isNotFor: ['coalaboard'], func: function(sprite, script) { let port = script.getStringField('PORT'); - let val = Entry.hw.portData[port].value; + let val = Entry.hw.portData[port].value; let pressed = script.getStringField('PRESSED'); - if ((pressed == 'pressed') && (val == 0)) { + if (pressed == 'pressed' && val == 0) { return true; - } else if ((pressed == 'released') && (val == 1023)) { + } else if (pressed == 'released' && val == 1023) { return true; } else { return false; - } + } }, syntax: { js: [], py: ['Coalaboard.is_touch_pressed(%1, %2)'] }, }, @@ -547,35 +551,35 @@ Entry.Coalaboard.getBlocks = function() { { type: 'text', params: ['100'], - } + }, ], type: 'coalaboard_is_sensor_value_compare', }, paramsKeyMap: { PORT: 0, INEQ_SIGN: 1, - VALUE: 2 + VALUE: 2, }, class: 'button', isNotFor: ['coalaboard'], func: function(sprite, script) { - let selectedPort = script.values[ 0 ]; - let ineqSign = script.values[ 1 ]; - let value = script.values[ 2 ]; - let port = script.getStringField('PORT'); - let val = Entry.hw.portData[port].value; - if( selectedPort == port && ineqSign == '<' && val < value ) { + let selectedPort = script.values[0]; + let ineqSign = script.values[1]; + let value = script.values[2]; + let port = script.getStringField('PORT'); + let val = Entry.hw.portData[port].value; + if (selectedPort == port && ineqSign == '<' && val < value) { return true; - } else if( selectedPort == port && ineqSign == '>' && val > value ) { + } else if (selectedPort == port && ineqSign == '>' && val > value) { return true; - } else if( selectedPort == port && ineqSign == '=' && val == value ) { + } else if (selectedPort == port && ineqSign == '=' && val == value) { return true; } else { return false; } }, syntax: { js: [], py: ['Bitbrick.is_sensor_value_compare(%1,%2,%3)'] }, - }, + }, coalaboard_turn_off_color_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -886,7 +890,7 @@ Entry.Coalaboard.getBlocks = function() { var value = script.getNumberValue('VALUE'); value = Math.min(value, Entry.Coalaboard.dcMaxValue); value = Math.max(value, Entry.Coalaboard.dcMinValue); - let val = Entry.Coalaboard.calculateDCMotorValue( value ); + let val = Entry.Coalaboard.calculateDCMotorValue(value); Entry.hw.sendQueue[script.getStringField('PORT')] = val; return script.callReturn(); }, @@ -949,13 +953,13 @@ Entry.Coalaboard.getBlocks = function() { isNotFor: ['coalaboard'], func: function(sprite, script) { let isFront = script.getStringField('DIRECTION') === 'CW'; - let value = script.getNumberValue('VALUE'); + let value = script.getNumberValue('VALUE'); value = Math.min(value, Entry.Coalaboard.dcMaxValue); value = Math.max(value, 0); - if ( !isFront ) { + if (!isFront) { value = -1 * value; } - let val = Entry.Coalaboard.calculateDCMotorValue( value ); + let val = Entry.Coalaboard.calculateDCMotorValue(value); Entry.hw.sendQueue[script.getStringField('PORT')] = val; return script.callReturn(); }, @@ -1027,7 +1031,8 @@ Entry.Coalaboard.setLanguage = function() { coalaboard_is_sensor_value_compare: '%1 값 %2 %3 인가?', coalaboard_sensor_value: '%1 값', coalaboard_convert_scale: '변환 %1 값 %2 ~ %3 에서 %4 ~ %5', - coalaboard_turn_on_color_led_by_rgb: '엘이디를 빨강 %1 초록 %2 파랑 %3 %4 (으)로 켜기', + coalaboard_turn_on_color_led_by_rgb: + '엘이디를 빨강 %1 초록 %2 파랑 %3 %4 (으)로 켜기', coalaboard_turn_on_color_led_by_picker: '엘이디를 %1 (으)로 켜기 %2', coalaboard_turn_on_color_led_by_value: '엘이디를 %1 (으)로 켜기 %2', coalaboard_turn_off_color_led: '엘이디 끄기 %1', @@ -1039,7 +1044,7 @@ Entry.Coalaboard.setLanguage = function() { }, Blocks: { COALABOARD_button_pressed: '누름', - COALABOARD_button_released: '누르지 않음', + COALABOARD_button_released: '누르지 않음', COALABOARD_light: '밝기 센서', COALABOARD_IR: '적외선 센서', COALABOARD_touch: '버튼', @@ -1060,17 +1065,20 @@ Entry.Coalaboard.setLanguage = function() { coalaboard: '코알라보드', }, Helper: { - coalaboard_when_button_pressed: '비트브릭 버튼을 누르면 아래에 연결된 블록들을 실행합니다.', + coalaboard_when_button_pressed: + '비트브릭 버튼을 누르면 아래에 연결된 블록들을 실행합니다.', coalaboard_when_sensor_get_value: '비트브릭 센서의 값과 오른쪽에 입력한 값을 비교합니다.\n< : 센서 값이 오른쪽에 위치한 값보다 작은 경우 ‘참’으로 판단합니다.\n> : 센서 값이 오른쪽에 위치한 값보다 큰 경우 ‘참으로 판단합니다.\n= : 센서 값이 오른쪽에 위치한 값과 같은 경우 ‘참으로 판단합니다.', coalaboard_sensor_value: '비트브릭 센서를 사용할 수 있는 블록입니다. 센서값의 범위는 0 ~1023입니다. 메인보드에 연결된 센서의 종류와 포트번호를 자동으로 인식합니다. 블록 안의 화살표를 눌러 사용하려고 하는 센서를 선택하세요.', coalaboard_convert_scale: '비트브릭 센서의 값의 범위를 바꿀 수 있습니다.', - coalaboard_is_touch_pressed: '비트브릭 센서 중 버튼을 눌렀을 경우 ‘참’으로 판단합니다.', + coalaboard_is_touch_pressed: + '비트브릭 센서 중 버튼을 눌렀을 경우 ‘참’으로 판단합니다.', coalaboard_turn_off_color_led: '비트브릭 엘이디를 끕니다.', coalaboard_turn_on_color_led_by_rgb: '비트브릭 엘이디를 빛의 삼원색인 빨강,초록,파랑을 혼합하여 켭니다. 값의 범위는 0 ~ 255입니다.', - coalaboard_turn_on_color_led_by_picker: '비트브릭 엘이디를 색상 창을 사용해 켭니다.', + coalaboard_turn_on_color_led_by_picker: + '비트브릭 엘이디를 색상 창을 사용해 켭니다.', coalaboard_turn_on_color_led_by_value: '비트브릭 엘이디를 색상 값으로 켭니다. 값의 범위는 0 ~ 199입니다.', coalaboard_buzzer: @@ -1081,8 +1089,8 @@ Entry.Coalaboard.setLanguage = function() { coalaboard_dc_direction_speed: '비트브릭 디씨모터의 방향과 속력을 제어합니다. 방향은 시계방향과 반시계방향을 선택할 수 있습니다. 속력 값의 범위는 0 ~ 100입니다. 속력이 0일 때는 회전을 멈춥니다.', coalaboard_servomotor_angle: - '비트브릭 서보모터의 각도를 제어합니다. 각도 값의 범위는 0 ~ 180입니다.' - } + '비트브릭 서보모터의 각도를 제어합니다. 각도 값의 범위는 0 ~ 180입니다.', + }, }, en: { // en.js에 작성하던 내용 @@ -1105,7 +1113,7 @@ Entry.Coalaboard.setLanguage = function() { }, Blocks: { COALABOARD_button_pressed: 'pressed', - COALABOARD_button_released: 'released', + COALABOARD_button_released: 'released', COALABOARD_light: 'light', COALABOARD_IR: 'IR', COALABOARD_touch: 'touch', diff --git a/src/playground/blocks/hardware/block_iCOBOT.js b/src/playground/blocks/hardware/block_iCOBOT.js index 702d697586..e703b6b513 100644 --- a/src/playground/blocks/hardware/block_iCOBOT.js +++ b/src/playground/blocks/hardware/block_iCOBOT.js @@ -824,7 +824,7 @@ Entry.iCOBOT.getBlocks = function() { setTimeout(function() { script.timeFlag = 0; - }, duration + 32); + }, duration + 50); // 통신중 딜레이를 고려하여 0.05초 더 기다림.. return script; } else if (script.timeFlag == 1) @@ -835,12 +835,12 @@ Entry.iCOBOT.getBlocks = function() { { delete script.timeFlag; delete script.isStart; - Entry.hw.sendQueue['SET'][port] = - { - type: Entry.iCOBOT.sensorTypes.TONE, - data: 0, - time: new Date().getTime(), - }; + // Entry.hw.sendQueue['SET'][port] = + // { + // type: Entry.iCOBOT.sensorTypes.TONE, + // data: 0, + // time: new Date().getTime(), + // }; Entry.engine.isContinue = false; return script.callReturn(); } diff --git a/src/playground/blocks/hardware/block_neo.js b/src/playground/blocks/hardware/block_neo.js new file mode 100644 index 0000000000..0585051572 --- /dev/null +++ b/src/playground/blocks/hardware/block_neo.js @@ -0,0 +1,5927 @@ +'use strict'; + +/* + 엔트리에 정의된 블럭 명령어 + 엔트리에서 받을 때는 BlockTypes 로 통신하고, + 하드웨어로 전송할 때는 Command 로 변환 후 Pdu 로 Wrapping 하여 전송한다. + */ +const NeoBlockType = { + // MOTOR 명령어 0x1X + MOTOR_MOVE: 0x11, + MOTOR_MOVE_BOTH: 0x12, + MOTOR_STOP: 0x13, + ROBOT_MOVE: 0x14, + ROBOT_STOP: 0x15, + // SERVO 명령어 0x2X + SERVO_RESET: 0x21, + SERVO_ANGLE: 0x22, + SERVO_ANGLE_WAIT: 0x23, + SERVO_ROTATE: 0x24, + SERVO_STOP: 0x25, + // LINE_TRACER 명령어 0x3X + LINE_TRACER_START: 0x31, + LINE_CROSS_MOVE: 0x32, + LINE_CROSS_TURN: 0x33, + LINE_CHANGE_START: 0x34, + LINE_CHANGE_TURN: 0x35, + // AUTO_DRIVING 명령어 0x4X + AUTO_DRIVING_START: 0x41, + AUTO_DRIVING_SENSOR_START: 0x42, + AUTO_DRIVING_STOP: 0x43, + AUTO_PARKING_START: 0x44, + AUTO_DETECT_WALL_START: 0x45, + AUTO_DETECT_WALL_TURN: 0x46, + // LED 명령어 0x5X + LED_ON: 0x51, + LED_BLINK: 0x52, + LED_OFF: 0x53, + COLOR_LED_ON: 0x54, + COLOR_LED_OFF: 0x55, + COLOR_LED_ON_SENSOR: 0x56, + // SET_OUTPUT 명령어 0x6X + SET_OUTPUT: 0x61, + // BUZZER 명령어 0x7X + BUZZER_START: 0x71, + BUZZER_WITH_SENSOR: 0x72, + BUZZER_STOP: 0x73, + // LCD 명령어 0x8X + LCD_IMAGE: 0x81, + LCD_TEXT: 0x82, +}; + +/* + PDU 정의 + */ +const HEADER = [0xaa, 0xaa, 0xcc]; + +const FrameCode = { + BASIC: 0x01, +}; + +const PduCode = { + SENSOR_DATA: 0x01, + CONTROLLER_COMMAND: 0x02, + ACTION_COMMAND: 0x03, + BASIC: 0x10, + EXTEND_1: 0x11, + EXTEND_2: 0x12, + EXTEND_3: 0x13, +}; + +const ActorKind = { + CONTROLLER: 0x00, + LED: 0x80, + SERVO: 0x81, + COLOR_LED: 0x82, + LCD: 0x83, +}; + +const ControllerCommand = { + CONTROLLER_LED: 0x01, + BUZZER: 0x02, + MOTOR: 0x03, + MOTOR_BOTH: 0x04, + ROBOT: 0x05, + LINE_TRACER: 0x06, + AUTO_DRIVING: 0x07, + AUTO_PARKING: 0x08, + AUTO_DETECT_WALL: 0x09, +}; + +const ServoCommand = { + STOP: 0x01, + RESET: 0x02, + ANGLE: 0x03, + ANGLE_WAIT: 0x04, + ROTATE: 0x05, +}; + +const LedCommand = { + OFF: 0x00, + ON: 0x01, +}; + +const LcdCommand = { + IMAGE: 0x01, + TEXT: 0x02, +}; + +const UnitId = { + CONTROLLER: 0x00, + CONTROLLER_IN1: 0x01, + CONTROLLER_IN2: 0x02, + CONTROLLER_IN3: 0x03, + SENSOR_STICK: 0x10, + SENSOR_STICK_IN1: 0x11, + IOT: 0x80, + CONTROLLER_OUT1: 0x81, + CONTROLLER_OUT2: 0x82, + CONTROLLER_OUT12: 0x83, + CONTROLLER_OUT3: 0x84, + CONTROLLER_OUT13: 0x85, + CONTROLLER_OUT23: 0x86, + CONTROLLER_OUT123: 0x87, + CONTROLLER_OUT_ALL: 0x8f, +}; + +/* + 블럭 실행 단계 + execute: 최초 실행 + pending_response: 최초 실행의 response 대기중인 상태 + set_timeout: 블럭에서 duration 필드에 의거하여 타임아웃을 설정 + wait_timeout: timeout 대기중인 상태 + stop: 파라미터를 0으로 바꿔서 실행 + pending_stop: 파라미터를 0으로 바꾼 실행의 response 대기중인 상태 + end: 실행 종료 단계 + */ +const ExecPhase = { + EXECUTE: 'execute', + PENDING_RESPONSE: 'pending_response', + SET_TIMEOUT: 'set_timeout', + WAIT_TIMEOUT: 'wait_timeout', + STOP: 'stop', + PENDING_STOP: 'pending_stop', + END: 'end', +}; + +/* + dropdown params + 양이 많아서 분리함. + */ +Entry.Neo = new (class Neo { + constructor() { + this.id = '5.8'; + this.url = 'http://www.neobot.co.kr'; + this.name = 'neo'; + this.imageName = 'neo.png'; + this.title = { + ko: '네오(NEO)', + en: 'NEO', + }; + this.blockMenuBlocks = [ + // motor & robot + 'neo_motor_title', + 'neo_motor_move', + 'neo_motor_move_both', + 'neo_robot_move', + 'neo_motor_stop', + 'neo_robot_stop', + // servo + 'neo_servo_title', + 'neo_servo_reset', + 'neo_servo_angle', + 'neo_servo_angle_var', + 'neo_servo_angle_wait', + 'neo_servo_rotate', + 'neo_servo_stop', + // line tracer + 'neo_line_tracer_title', + 'neo_line_tracer_start', + 'neo_line_cross_move', + 'neo_line_cross_turn', + // auto driving + 'neo_auto_driving_title', + 'neo_auto_driving_start', + 'neo_auto_driving_sensor_start', + 'neo_auto_driving_stop', + // auto parking + 'neo_auto_parking_title', + 'neo_auto_parking_start', + /*// line change + 'neo_line_change_title', + 'neo_line_change_start', + 'neo_line_change_turn', + // auto detect wall + 'neo_auto_detect_wall_title', + 'neo_auto_detect_wall_start', + 'neo_auto_detect_wall_turn',*/ + // led + 'neo_led_title', + 'neo_led_on', + 'neo_led_blink', + 'neo_led_off', + // color led + 'neo_color_led_title', + 'neo_color_led_on', + 'neo_color_led_off', + 'neo_color_led_on_with_sensor', + // set output + 'neo_set_output_title', + 'neo_set_output', + // sensor + 'neo_sensor_title', + 'neo_sensor_in', + 'neo_sensor_digital_in', + 'neo_sensor_convert', + 'neo_sensor_compare', + 'neo_sensor_between', + 'neo_sensor_color_compare', + 'neo_sensor_button_pressed', + // lcd + 'neo_lcd_title', + 'neo_lcd_image', + 'neo_lcd_text', + // buzzer + 'neo_buzzer_title', + 'neo_buzzer_start', + 'neo_buzzer_with_sensor', + 'neo_buzzer_stop', + ]; + this.seqBlockId = 0; + this.executeList = {}; + this.pendingResponseList = {}; + this.monitorTemplate = { + imgPath: 'hw/neo.png', + width: 500, + height: 500, + listPorts: { + IN11: { name: 'IN1 1', type: 'input', pos: { x: 0, y: 0 } }, + IN12: { name: 'IN1 2', type: 'input', pos: { x: 0, y: 0 } }, + IN13: { name: 'IN1 3', type: 'input', pos: { x: 0, y: 0 } }, + IN14: { name: 'IN1 4', type: 'input', pos: { x: 0, y: 0 } }, + IN21: { name: 'IN2 1', type: 'input', pos: { x: 0, y: 0 } }, + IN22: { name: 'IN2 2', type: 'input', pos: { x: 0, y: 0 } }, + IN23: { name: 'IN2 3', type: 'input', pos: { x: 0, y: 0 } }, + IN24: { name: 'IN2 4', type: 'input', pos: { x: 0, y: 0 } }, + IN31: { name: 'IN3 1', type: 'input', pos: { x: 0, y: 0 } }, + IN32: { name: 'IN3 2', type: 'input', pos: { x: 0, y: 0 } }, + IN33: { name: 'IN3 3', type: 'input', pos: { x: 0, y: 0 } }, + IN34: { name: 'IN3 4', type: 'input', pos: { x: 0, y: 0 } }, + IR: { name: 'IR', type: 'input', pos: { x: 0, y: 0 } }, + BAT: { name: 'BAT', type: 'input', pos: { x: 0, y: 0 } }, + }, + mode: 'both', + }; + } + + setZero() { + const blockId = this.generateBlockId(); + const pdu = this.makePdu([FrameCode.BASIC, PduCode.CONTROLLER_COMMAND, blockId, 0x04]); + Entry.hw.sendQueue.executeList = { + blockId: { + blockId, + pdu, + }, + }; + Entry.hw.update(); + + this.pendingResponseList = {}; + this.executeList = {}; + } + + afterReceive(portData) { + for (let i = 0; i <= 255; i++) { + if (this.pendingResponseList[i]) { + if (portData.pendingList[i] && portData.pendingList[i].state === 'completed') { + delete this.pendingResponseList[i]; + delete this.executeList[i]; + } + } + } + } + + generateBlockId() { + this.seqBlockId += 1; + if (this.seqBlockId > 255) { + this.seqBlockId = 1; + } + return this.seqBlockId; + } + + setLanguage() { + return { + ko: { + template: { + // motor & robot + neo_motor_title: '회전모터', + neo_motor_move: '회전모터 제어하기 %1 %2 %3 %4', + neo_motor_move_both: '회전모터 동시에 제어하기 L %1 R %2 %3', + neo_robot_move: '로봇 제어하기 %1 %2 %3 %4', + neo_motor_stop: '회전모터 멈추기 %1 %2', + neo_robot_stop: '로봇 멈추기 %1', + + // servo + neo_servo_title: '서보모터', + neo_servo_reset: '%1 서보모터 현위치를 0도로 설정하기 %2', + neo_servo_angle: '서보모터 각도 바꾸기 %1 %2 %3 %4', + neo_servo_angle_var: '서보모터 각도 바꾸기 %1 %2 %3 %4', + neo_servo_angle_wait: '각도 바뀔때까지 기다리기 %1 %2 %3 %4', + neo_servo_rotate: '서보모터 회전하기 %1 %2 %3 %4', + neo_servo_stop: '서보모터 멈추기 %1 %2', + + // line tracer + neo_line_tracer_title: '라인트레이서', + neo_line_tracer_start: '검은색 선 따라가기 %1 %2 %3', + neo_line_cross_move: '%1 교차로까지 직진하기 %2', + neo_line_cross_turn: '다음 교차로에서 방향바꾸기 %1 %2', + + // auto driving + neo_auto_driving_title: '자율주행', + neo_auto_driving_start: '자율주행 시작하기 %1 %2 %3', + neo_auto_driving_sensor_start: '%1 를 감지하여 자율주행 %2 %3', + neo_auto_driving_stop: '자율주행 멈추기 %1', + + // auto parking + neo_auto_parking_title: '자율주차', + neo_auto_parking_start: '주차하기 %1 %2 %3', + + // line change + neo_line_change_title: '차선 변경', + neo_line_change_start: '%1 차로 변경하기 %2', + neo_line_change_turn: '교차로에서 회전하기 %1 %2', + + // auto detect wall + neo_auto_detect_wall_title: '골목주행', + neo_auto_detect_wall_start: '벽 탐지하며 주행하기 %1 %2 %3', + neo_auto_detect_wall_turn: '골목에서 회전하기 %1 %2', + + // led + neo_led_title: 'LED', + neo_led_on: 'LED 켜기 %1 %2 %3', + neo_led_blink: 'LED 깜빡이기 %1 %2 %3 %4', + neo_led_off: 'LED 끄기 %1 %2', + + // color led + neo_color_led_title: '컬러 LED', + neo_color_led_on: '컬러LED 켜기 %1 %2 %3 %4', + neo_color_led_off: '컬러LED 끄기 %1 %2', + neo_color_led_on_with_sensor: '컬러센서 %1 로 컬러LED %2 제어 %3', + + // set output + neo_set_output_title: '출력', + neo_set_output: '값 출력하기 %1 %2 %3 %4', + + // sensor + neo_sensor_title: '센서', + neo_sensor_in: '%1', + neo_sensor_digital_in: '%1 의 %2', + neo_sensor_convert: '%1 %2 %3 → %4 %5', + neo_sensor_compare: '%1 %2 %3', + neo_sensor_between: '%1 %2 %3 %4 %5', + neo_sensor_color_compare: '%1 = %2', + neo_sensor_button_pressed: '%1 %2', + + // buzzer + neo_buzzer_title: '버저', + neo_buzzer_start: '버저 울리기 %1 %2 %3 %4', + neo_buzzer_with_sensor: '센서로 버저 울리기 %1 %2', + neo_buzzer_stop: '버저 멈추기 %1', + + // lcd + neo_lcd_title: 'LCD', + neo_lcd_image: 'LCD에 이미지 보여주기 %1 %2 %3', + neo_lcd_text: 'LCD에 텍스트 보여주기 %1 %2 %3', + + // args + neo_arg_motor_speed: '%1', + neo_arg_duration: '%1', + neo_arg_robot_speed: '%1', + neo_arg_servo_angle: '%1', + neo_arg_servo_speed: '%1', + neo_arg_auto_driving_speed: '%1', + neo_arg_led_brightness: '%1', + neo_arg_led_blink_speed: '%1', + neo_arg_set_output_value: '%1', + }, + Blocks: { + neo_input_1: 'IN1', + neo_input_2: 'IN2', + neo_input_3: 'IN3', + neo_input_12: 'IN1&2', + neo_input_123: 'IN1&2&3', + neo_input_1_2: 'IN1&IN2', + neo_input_11_12: 'IN1-1&IN1-2', + neo_input_13_14: 'IN1-3&IN1-4', + neo_input_21_22: 'IN2-1&IN2-2', + neo_input_23_24: 'IN2-3&IN2-4', + + neo_output_1: 'OUT1', + neo_output_2: 'OUT2', + neo_output_3: 'OUT3', + neo_output_12: 'OUT1&2', + neo_output_123: 'OUT1&2&3', + + neo_speed_0: '0%', + neo_speed_5: '5%', + neo_speed_10: '10%', + neo_speed_15: '15%', + neo_speed_20: '20%', + neo_speed_25: '25%', + neo_speed_30: '30%', + neo_speed_35: '35%', + neo_speed_40: '40%', + neo_speed_45: '45%', + neo_speed_50: '50%', + neo_speed_55: '55%', + neo_speed_60: '60%', + neo_speed_65: '65%', + neo_speed_70: '70%', + neo_speed_75: '75%', + neo_speed_80: '80%', + neo_speed_85: '85%', + neo_speed_90: '90%', + neo_speed_95: '95%', + neo_speed_100: '100%', + + neo_duration_c: '계속', + neo_duration_0: '0초', + neo_duration_1: '1초', + neo_duration_2: '2초', + neo_duration_3: '3초', + neo_duration_4: '4초', + neo_duration_5: '5초', + neo_duration_6: '6초', + neo_duration_7: '7초', + neo_duration_8: '8초', + neo_duration_9: '9초', + + neo_compare_gt: '≥', + neo_compare_g: '>', + neo_compare_e: '=', + neo_compare_l: '<', + neo_compare_lt: '≤', + + neo_turn_direction_l: '좌회전', + neo_turn_direction_r: '우회전', + neo_turn_direction_u: 'U턴', + + neo_motor_out_l: 'L모터', + neo_motor_out_r: 'R모터', + neo_motor_out_lr: 'L/R모터', + + neo_motor_speed_n100: '-100%', + neo_motor_speed_n95: '-95%', + neo_motor_speed_n90: '-90%', + neo_motor_speed_n85: '-85%', + neo_motor_speed_n80: '-80%', + neo_motor_speed_n75: '-75%', + neo_motor_speed_n70: '-70%', + neo_motor_speed_n65: '-65%', + neo_motor_speed_n60: '-60%', + neo_motor_speed_n55: '-55%', + neo_motor_speed_n50: '-50%', + neo_motor_speed_n45: '-45%', + neo_motor_speed_n40: '-40%', + neo_motor_speed_n35: '-35%', + neo_motor_speed_n30: '-30%', + neo_motor_speed_n25: '-25%', + neo_motor_speed_n20: '-20%', + neo_motor_speed_n15: '-15%', + neo_motor_speed_n10: '-10%', + neo_motor_speed_n5: '-5%', + neo_motor_speed_0: '0%', + neo_motor_speed_5: '5%', + neo_motor_speed_10: '10%', + neo_motor_speed_15: '15%', + neo_motor_speed_20: '20%', + neo_motor_speed_25: '25%', + neo_motor_speed_30: '30%', + neo_motor_speed_35: '35%', + neo_motor_speed_40: '40%', + neo_motor_speed_45: '45%', + neo_motor_speed_50: '50%', + neo_motor_speed_55: '55%', + neo_motor_speed_60: '60%', + neo_motor_speed_65: '65%', + neo_motor_speed_70: '70%', + neo_motor_speed_75: '75%', + neo_motor_speed_80: '80%', + neo_motor_speed_85: '85%', + neo_motor_speed_90: '90%', + neo_motor_speed_95: '95%', + neo_motor_speed_100: '100%', + + neo_robot_direction_f: '앞으로', + neo_robot_direction_b: '뒤로', + neo_robot_direction_l: '왼쪽으로', + neo_robot_direction_r: '오른쪽으로', + neo_robot_direction_tl: '제자리왼쪽', + neo_robot_direction_tr: '제자리오른쪽', + + neo_servo_angle_n360: '-360도', + neo_servo_angle_n350: '-350도', + neo_servo_angle_n340: '-340도', + neo_servo_angle_n330: '-330도', + neo_servo_angle_n320: '-320도', + neo_servo_angle_n310: '-310도', + neo_servo_angle_n300: '-300도', + neo_servo_angle_n290: '-290도', + neo_servo_angle_n280: '-280도', + neo_servo_angle_n270: '-270도', + neo_servo_angle_n260: '-260도', + neo_servo_angle_n250: '-250도', + neo_servo_angle_n240: '-240도', + neo_servo_angle_n230: '-230도', + neo_servo_angle_n220: '-220도', + neo_servo_angle_n210: '-210도', + neo_servo_angle_n200: '-200도', + neo_servo_angle_n190: '-190도', + neo_servo_angle_n180: '-180도', + neo_servo_angle_n170: '-170도', + neo_servo_angle_n160: '-160도', + neo_servo_angle_n150: '-150도', + neo_servo_angle_n140: '-140도', + neo_servo_angle_n130: '-130도', + neo_servo_angle_n120: '-120도', + neo_servo_angle_n110: '-110도', + neo_servo_angle_n100: '-100도', + neo_servo_angle_n90: '-90도', + neo_servo_angle_n80: '-80도', + neo_servo_angle_n70: '-70도', + neo_servo_angle_n60: '-60도', + neo_servo_angle_n50: '-50도', + neo_servo_angle_n40: '-40도', + neo_servo_angle_n30: '-30도', + neo_servo_angle_n20: '-20도', + neo_servo_angle_n10: '-10도', + neo_servo_angle_0: '0도', + neo_servo_angle_10: '10도', + neo_servo_angle_20: '20도', + neo_servo_angle_30: '30도', + neo_servo_angle_40: '40도', + neo_servo_angle_50: '50도', + neo_servo_angle_60: '60도', + neo_servo_angle_70: '70도', + neo_servo_angle_80: '80도', + neo_servo_angle_90: '90도', + neo_servo_angle_100: '100도', + neo_servo_angle_110: '110도', + neo_servo_angle_120: '120도', + neo_servo_angle_130: '130도', + neo_servo_angle_140: '140도', + neo_servo_angle_150: '150도', + neo_servo_angle_160: '160도', + neo_servo_angle_170: '170도', + neo_servo_angle_180: '180도', + neo_servo_angle_190: '190도', + neo_servo_angle_200: '200도', + neo_servo_angle_210: '210도', + neo_servo_angle_220: '220도', + neo_servo_angle_230: '230도', + neo_servo_angle_240: '240도', + neo_servo_angle_250: '250도', + neo_servo_angle_260: '260도', + neo_servo_angle_270: '270도', + neo_servo_angle_280: '280도', + neo_servo_angle_290: '290도', + neo_servo_angle_300: '300도', + neo_servo_angle_310: '310도', + neo_servo_angle_320: '320도', + neo_servo_angle_330: '330도', + neo_servo_angle_340: '340도', + neo_servo_angle_350: '350도', + neo_servo_angle_360: '360도', + + neo_servo_direction_f: '앞으로', + neo_servo_direction_b: '뒤로', + + neo_line_cross_move_1: '1번째', + neo_line_cross_move_2: '2번째', + neo_line_cross_move_3: '3번째', + neo_line_cross_move_4: '4번째', + neo_line_cross_move_5: '5번째', + neo_line_cross_move_6: '6번째', + neo_line_cross_move_7: '7번째', + neo_line_cross_move_8: '8번째', + neo_line_cross_move_9: '9번째', + neo_line_cross_move_10: '10번째', + + neo_line_cross_turn_direction_l: '좌회전', + neo_line_cross_turn_direction_r: '우회전', + neo_line_cross_turn_direction_u: 'U턴', + + neo_auto_driving_speed_in3: 'IN3', + + neo_auto_parking_which_l: '왼쪽에', + neo_auto_parking_which_r: '오른쪽에', + + neo_auto_parking_direction_b: '후면주차', + neo_auto_parking_direction_s: '평행주차', + + neo_line_change_direction_l: '왼쪽으로', + neo_line_change_direction_r: '오른쪽으로', + + neo_line_change_turn_direction_l: '좌회전', + neo_line_change_turn_direction_r: '우회전', + neo_line_change_turn_direction_u: 'U턴', + + neo_led_brightness_0: '0%', + neo_led_brightness_5: '5%', + neo_led_brightness_10: '10%', + neo_led_brightness_15: '15%', + neo_led_brightness_20: '20%', + neo_led_brightness_25: '25%', + neo_led_brightness_30: '30%', + neo_led_brightness_35: '35%', + neo_led_brightness_40: '40%', + neo_led_brightness_45: '45%', + neo_led_brightness_50: '50%', + neo_led_brightness_55: '55%', + neo_led_brightness_60: '60%', + neo_led_brightness_65: '65%', + neo_led_brightness_70: '70%', + neo_led_brightness_75: '75%', + neo_led_brightness_80: '80%', + neo_led_brightness_85: '85%', + neo_led_brightness_90: '90%', + neo_led_brightness_95: '95%', + neo_led_brightness_100: '100%', + + neo_led_blink_speed_1: '1단계', + neo_led_blink_speed_2: '2단계', + neo_led_blink_speed_3: '3단계', + neo_led_blink_speed_4: '4단계', + neo_led_blink_speed_5: '5단계', + + neo_set_output_value_0: '0', + neo_set_output_value_5: '5', + neo_set_output_value_10: '10', + neo_set_output_value_15: '15', + neo_set_output_value_20: '20', + neo_set_output_value_25: '25', + neo_set_output_value_30: '30', + neo_set_output_value_35: '35', + neo_set_output_value_40: '40', + neo_set_output_value_45: '45', + neo_set_output_value_50: '50', + neo_set_output_value_55: '55', + neo_set_output_value_60: '60', + neo_set_output_value_65: '65', + neo_set_output_value_70: '70', + neo_set_output_value_75: '75', + neo_set_output_value_80: '80', + neo_set_output_value_85: '85', + neo_set_output_value_90: '90', + neo_set_output_value_95: '95', + neo_set_output_value_100: '100', + neo_set_output_value_105: '105', + neo_set_output_value_110: '110', + neo_set_output_value_115: '115', + neo_set_output_value_120: '120', + neo_set_output_value_125: '125', + neo_set_output_value_130: '130', + neo_set_output_value_135: '135', + neo_set_output_value_140: '140', + neo_set_output_value_145: '145', + neo_set_output_value_150: '150', + neo_set_output_value_155: '155', + neo_set_output_value_160: '160', + neo_set_output_value_165: '165', + neo_set_output_value_170: '170', + neo_set_output_value_175: '175', + neo_set_output_value_180: '180', + neo_set_output_value_185: '185', + neo_set_output_value_190: '190', + neo_set_output_value_195: '195', + neo_set_output_value_200: '200', + neo_set_output_value_205: '205', + neo_set_output_value_210: '210', + neo_set_output_value_215: '215', + neo_set_output_value_220: '220', + neo_set_output_value_225: '225', + neo_set_output_value_230: '230', + neo_set_output_value_235: '235', + neo_set_output_value_240: '240', + neo_set_output_value_245: '245', + neo_set_output_value_250: '250', + neo_set_output_value_255: '255', + + neo_sensor_in_digital_1: '1번', + neo_sensor_in_digital_2: '2번', + neo_sensor_in_digital_3: '3번', + neo_sensor_in_digital_4: '4번', + + neo_color_black: '검정', + neo_color_white: '흰색', + neo_color_red: '빨강', + neo_color_yellow: '노랑', + neo_color_green: '녹색', + neo_color_blue: '파랑', + + neo_button_1: '버튼1', + neo_button_2: '버튼2', + neo_button_3: '버튼3', + neo_button_4: '버튼4', + + neo_button_on: 'ON', + neo_button_off: 'OFF', + + neo_buzzer_octave_1: '1옥타브', + neo_buzzer_octave_2: '2옥타브', + neo_buzzer_octave_3: '3옥타브', + neo_buzzer_octave_4: '4옥타브', + neo_buzzer_octave_5: '5옥타브', + neo_buzzer_octave_6: '6옥타브', + + neo_buzzer_do: '도', + neo_buzzer_do_sharp: '도#', + neo_buzzer_re: '레', + neo_buzzer_re_sharp: '레#', + neo_buzzer_mi: '미', + neo_buzzer_fa: '파', + neo_buzzer_fa_sharp: '파#', + neo_buzzer_sol: '솔', + neo_buzzer_sol_sharp: '솔#', + neo_buzzer_la: '라', + neo_buzzer_la_sharp: '라#', + neo_buzzer_ti: '시', + + neo_buzzer_whole_note: '온음표', + neo_buzzer_half_note: '2분 음표', + neo_buzzer_quarter_note: '4분 음표', + neo_buzzer_8th_note: '8분 음표', + + neo_lcd_image_1: '1', + neo_lcd_image_2: '2', + neo_lcd_image_3: '3', + neo_lcd_image_4: '4', + neo_lcd_image_5: '5', + neo_lcd_image_6: '6', + neo_lcd_image_7: '7', + neo_lcd_image_8: '8', + neo_lcd_image_9: '9', + neo_lcd_image_10: '10', + neo_lcd_image_11: '11', + neo_lcd_image_12: '12', + neo_lcd_image_13: '13', + neo_lcd_image_14: '14', + neo_lcd_image_15: '15', + }, + }, + en: { + // en.js에 작성하던 내용 + template: { + // motor & robot + // motor & robot + neo_motor_title: 'Motor', + neo_motor_move: 'Move motor %1 %2 %3 %4', + neo_motor_move_both: 'Move both motor L %1 R %2 %3', + neo_robot_move: 'Move robot %1 %2 %3 %4', + neo_motor_stop: 'Stop motor %1 %2', + neo_robot_stop: 'Stop robot %1', + + // servo + neo_servo_title: 'Servo motor', + neo_servo_reset: 'Reset the current position of %1 servo motor to 0 degree %2', + neo_servo_angle: 'Change servo angle %1 %2 %3 %4', + neo_servo_angle_var: 'Change servo angle %1 %2 %3 %4', + neo_servo_angle_wait: 'Wait to change servo angle %1 %2 %3 %4', + neo_servo_rotate: 'Rotate servo motor %1 %2 %3 %4', + neo_servo_stop: 'Stop servo motor %1 %2', + + // line tracer + neo_line_tracer_title: 'Line tracer', + neo_line_tracer_start: 'Start line tracer with black line %1 %2 %3', + neo_line_cross_move: 'Keep moving to the %1 intersection %2', + neo_line_cross_turn: 'Turn at the next intersection %1 %2', + + // auto driving + neo_auto_driving_title: 'Self-driving', + neo_auto_driving_start: 'Start self-driving %1 %2 %3', + neo_auto_driving_sensor_start: 'Start self-driving with %1 %2 %3', + neo_auto_driving_stop: 'Stop self-driving %1', + + // auto parking + neo_auto_parking_title: 'Auto parking', + neo_auto_parking_start: 'Start auto parking %1 %2 %3', + + // line change + neo_line_change_title: 'Lane change', + neo_line_change_start: 'Change Lane %1 %2', + neo_line_change_turn: 'Turn at the intersection %1 %2', + + // auto detect wall + neo_auto_detect_wall_title: 'Alley driving', + neo_auto_detect_wall_start: 'Start alley driving %1 %2 %3', + neo_auto_detect_wall_turn: 'Turn in the alley %1 %2', + + // led + neo_led_title: 'LED', + neo_led_on: 'Turn on the LED %1 %2 %3', + neo_led_blink: 'Blink the LED %1 %2 %3 %4', + neo_led_off: 'Turn off the LED %1 %2', + + // color led + neo_color_led_title: 'Color LED', + neo_color_led_on: 'Turn on the color LED %1 %2 %3 %4', + neo_color_led_off: 'Turn off the color LED %1 %2', + neo_color_led_on_with_sensor: 'Turn on the color LED %2 with color sensor %1 %3', + + // set output + neo_set_output_title: 'Set output', + neo_set_output: 'Set output %1 %2 %3 %4', + + // sensor + neo_sensor_title: 'Sensor', + neo_sensor_in: '%1', + neo_sensor_digital_in: '%1 %2', + neo_sensor_convert: '%1 %2 %3 → %4 %5', + neo_sensor_compare: '%1 %2 %3', + neo_sensor_between: '%1 %2 %3 %4 %5', + neo_sensor_color_compare: '%1 = %2', + neo_sensor_button_pressed: '%1 %2', + + // buzzer + neo_buzzer_title: 'Buzzer', + neo_buzzer_start: 'Buzzer %1 %2 %3 %4', + neo_buzzer_with_sensor: 'Buzzer by sensor value %1 %2', + neo_buzzer_stop: 'Stop the buzzer %1', + + // lcd + neo_lcd_title: 'LCD', + neo_lcd_image: 'Show image on LCD %1 %2 %3', + neo_lcd_text: 'Show text on LCD %1 %2 %3', + + // args + neo_arg_motor_speed: '%1', + neo_arg_duration: '%1', + neo_arg_robot_speed: '%1', + neo_arg_servo_angle: '%1', + neo_arg_servo_speed: '%1', + neo_arg_auto_driving_speed: '%1', + neo_arg_led_brightness: '%1', + neo_arg_led_blink_speed: '%1', + neo_arg_set_output_value: '%1', + }, + Blocks: { + neo_input_1: 'IN1', + neo_input_2: 'IN2', + neo_input_3: 'IN3', + neo_input_12: 'IN1&2', + neo_input_123: 'IN1&2&3', + neo_input_1_2: 'IN1&IN2', + neo_input_11_12: 'IN1-1&IN1-2', + neo_input_13_14: 'IN1-3&IN1-4', + neo_input_21_22: 'IN2-1&IN2-2', + neo_input_23_24: 'IN2-3&IN2-4', + + neo_output_1: 'OUT1', + neo_output_2: 'OUT2', + neo_output_3: 'OUT3', + neo_output_12: 'OUT1&2', + neo_output_123: 'OUT1&2&3', + + neo_speed_0: '0%', + neo_speed_5: '5%', + neo_speed_10: '10%', + neo_speed_15: '15%', + neo_speed_20: '20%', + neo_speed_25: '25%', + neo_speed_30: '30%', + neo_speed_35: '35%', + neo_speed_40: '40%', + neo_speed_45: '45%', + neo_speed_50: '50%', + neo_speed_55: '55%', + neo_speed_60: '60%', + neo_speed_65: '65%', + neo_speed_70: '70%', + neo_speed_75: '75%', + neo_speed_80: '80%', + neo_speed_85: '85%', + neo_speed_90: '90%', + neo_speed_95: '95%', + neo_speed_100: '100%', + + neo_duration_c: 'constantly', + neo_duration_0: '0 second', + neo_duration_1: '1 second', + neo_duration_2: '2 second', + neo_duration_3: '3 second', + neo_duration_4: '4 second', + neo_duration_5: '5 second', + neo_duration_6: '6 second', + neo_duration_7: '7 second', + neo_duration_8: '8 second', + neo_duration_9: '9 second', + + neo_compare_gt: '≥', + neo_compare_g: '>', + neo_compare_e: '=', + neo_compare_l: '<', + neo_compare_lt: '≤', + + neo_turn_direction_l: 'left', + neo_turn_direction_r: 'right', + neo_turn_direction_u: 'U-turn', + + neo_motor_out_l: 'left', + neo_motor_out_r: 'right', + neo_motor_out_lr: 'both', + + neo_motor_speed_n100: '-100%', + neo_motor_speed_n95: '-95%', + neo_motor_speed_n90: '-90%', + neo_motor_speed_n85: '-85%', + neo_motor_speed_n80: '-80%', + neo_motor_speed_n75: '-75%', + neo_motor_speed_n70: '-70%', + neo_motor_speed_n65: '-65%', + neo_motor_speed_n60: '-60%', + neo_motor_speed_n55: '-55%', + neo_motor_speed_n50: '-50%', + neo_motor_speed_n45: '-45%', + neo_motor_speed_n40: '-40%', + neo_motor_speed_n35: '-35%', + neo_motor_speed_n30: '-30%', + neo_motor_speed_n25: '-25%', + neo_motor_speed_n20: '-20%', + neo_motor_speed_n15: '-15%', + neo_motor_speed_n10: '-10%', + neo_motor_speed_n5: '-5%', + neo_motor_speed_0: '0%', + neo_motor_speed_5: '5%', + neo_motor_speed_10: '10%', + neo_motor_speed_15: '15%', + neo_motor_speed_20: '20%', + neo_motor_speed_25: '25%', + neo_motor_speed_30: '30%', + neo_motor_speed_35: '35%', + neo_motor_speed_40: '40%', + neo_motor_speed_45: '45%', + neo_motor_speed_50: '50%', + neo_motor_speed_55: '55%', + neo_motor_speed_60: '60%', + neo_motor_speed_65: '65%', + neo_motor_speed_70: '70%', + neo_motor_speed_75: '75%', + neo_motor_speed_80: '80%', + neo_motor_speed_85: '85%', + neo_motor_speed_90: '90%', + neo_motor_speed_95: '95%', + neo_motor_speed_100: '100%', + + neo_robot_direction_f: 'forward', + neo_robot_direction_b: 'backward', + neo_robot_direction_l: 'left', + neo_robot_direction_r: 'right', + neo_robot_direction_tl: 'left in place', + neo_robot_direction_tr: 'right in place', + + neo_servo_angle_n360: '-360 degree', + neo_servo_angle_n350: '-350 degree', + neo_servo_angle_n340: '-340 degree', + neo_servo_angle_n330: '-330 degree', + neo_servo_angle_n320: '-320 degree', + neo_servo_angle_n310: '-310 degree', + neo_servo_angle_n300: '-300 degree', + neo_servo_angle_n290: '-290 degree', + neo_servo_angle_n280: '-280 degree', + neo_servo_angle_n270: '-270 degree', + neo_servo_angle_n260: '-260 degree', + neo_servo_angle_n250: '-250 degree', + neo_servo_angle_n240: '-240 degree', + neo_servo_angle_n230: '-230 degree', + neo_servo_angle_n220: '-220 degree', + neo_servo_angle_n210: '-210 degree', + neo_servo_angle_n200: '-200 degree', + neo_servo_angle_n190: '-190 degree', + neo_servo_angle_n180: '-180 degree', + neo_servo_angle_n170: '-170 degree', + neo_servo_angle_n160: '-160 degree', + neo_servo_angle_n150: '-150 degree', + neo_servo_angle_n140: '-140 degree', + neo_servo_angle_n130: '-130 degree', + neo_servo_angle_n120: '-120 degree', + neo_servo_angle_n110: '-110 degree', + neo_servo_angle_n100: '-100 degree', + neo_servo_angle_n90: '-90 degree', + neo_servo_angle_n80: '-80 degree', + neo_servo_angle_n70: '-70 degree', + neo_servo_angle_n60: '-60 degree', + neo_servo_angle_n50: '-50 degree', + neo_servo_angle_n40: '-40 degree', + neo_servo_angle_n30: '-30 degree', + neo_servo_angle_n20: '-20 degree', + neo_servo_angle_n10: '-10 degree', + neo_servo_angle_0: '0 degree', + neo_servo_angle_10: '10 degree', + neo_servo_angle_20: '20 degree', + neo_servo_angle_30: '30 degree', + neo_servo_angle_40: '40 degree', + neo_servo_angle_50: '50 degree', + neo_servo_angle_60: '60 degree', + neo_servo_angle_70: '70 degree', + neo_servo_angle_80: '80 degree', + neo_servo_angle_90: '90 degree', + neo_servo_angle_100: '100 degree', + neo_servo_angle_110: '110 degree', + neo_servo_angle_120: '120 degree', + neo_servo_angle_130: '130 degree', + neo_servo_angle_140: '140 degree', + neo_servo_angle_150: '150 degree', + neo_servo_angle_160: '160 degree', + neo_servo_angle_170: '170 degree', + neo_servo_angle_180: '180 degree', + neo_servo_angle_190: '190 degree', + neo_servo_angle_200: '200 degree', + neo_servo_angle_210: '210 degree', + neo_servo_angle_220: '220 degree', + neo_servo_angle_230: '230 degree', + neo_servo_angle_240: '240 degree', + neo_servo_angle_250: '250 degree', + neo_servo_angle_260: '260 degree', + neo_servo_angle_270: '270 degree', + neo_servo_angle_280: '280 degree', + neo_servo_angle_290: '290 degree', + neo_servo_angle_300: '300 degree', + neo_servo_angle_310: '310 degree', + neo_servo_angle_320: '320 degree', + neo_servo_angle_330: '330 degree', + neo_servo_angle_340: '340 degree', + neo_servo_angle_350: '350 degree', + neo_servo_angle_360: '360 degree', + + neo_servo_direction_f: 'forward', + neo_servo_direction_b: 'backward', + + neo_line_cross_move_1: '1st', + neo_line_cross_move_2: '2nd', + neo_line_cross_move_3: '3rd', + neo_line_cross_move_4: '4th', + neo_line_cross_move_5: '5th', + neo_line_cross_move_6: '6th', + neo_line_cross_move_7: '7th', + neo_line_cross_move_8: '8th', + neo_line_cross_move_9: '9th', + neo_line_cross_move_10: '10th', + + neo_line_cross_turn_direction_l: 'to left', + neo_line_cross_turn_direction_r: 'to right', + neo_line_cross_turn_direction_u: 'U-turn', + + neo_auto_driving_speed_in3: 'IN3', + + neo_auto_parking_which_l: 'to left', + neo_auto_parking_which_r: 'to right', + + neo_auto_parking_direction_b: 'rear parking', + neo_auto_parking_direction_s: 'parallel parking', + + neo_line_change_direction_l: 'to left', + neo_line_change_direction_r: 'to right', + + neo_line_change_turn_direction_l: 'to left', + neo_line_change_turn_direction_r: 'to right', + neo_line_change_turn_direction_u: 'U-turn', + + neo_led_brightness_0: '0%', + neo_led_brightness_5: '5%', + neo_led_brightness_10: '10%', + neo_led_brightness_15: '15%', + neo_led_brightness_20: '20%', + neo_led_brightness_25: '25%', + neo_led_brightness_30: '30%', + neo_led_brightness_35: '35%', + neo_led_brightness_40: '40%', + neo_led_brightness_45: '45%', + neo_led_brightness_50: '50%', + neo_led_brightness_55: '55%', + neo_led_brightness_60: '60%', + neo_led_brightness_65: '65%', + neo_led_brightness_70: '70%', + neo_led_brightness_75: '75%', + neo_led_brightness_80: '80%', + neo_led_brightness_85: '85%', + neo_led_brightness_90: '90%', + neo_led_brightness_95: '95%', + neo_led_brightness_100: '100%', + + neo_led_blink_speed_1: '1 step', + neo_led_blink_speed_2: '2 step', + neo_led_blink_speed_3: '3 step', + neo_led_blink_speed_4: '4 step', + neo_led_blink_speed_5: '5 step', + + neo_set_output_value_0: '0', + neo_set_output_value_5: '5', + neo_set_output_value_10: '10', + neo_set_output_value_15: '15', + neo_set_output_value_20: '20', + neo_set_output_value_25: '25', + neo_set_output_value_30: '30', + neo_set_output_value_35: '35', + neo_set_output_value_40: '40', + neo_set_output_value_45: '45', + neo_set_output_value_50: '50', + neo_set_output_value_55: '55', + neo_set_output_value_60: '60', + neo_set_output_value_65: '65', + neo_set_output_value_70: '70', + neo_set_output_value_75: '75', + neo_set_output_value_80: '80', + neo_set_output_value_85: '85', + neo_set_output_value_90: '90', + neo_set_output_value_95: '95', + neo_set_output_value_100: '100', + neo_set_output_value_105: '105', + neo_set_output_value_110: '110', + neo_set_output_value_115: '115', + neo_set_output_value_120: '120', + neo_set_output_value_125: '125', + neo_set_output_value_130: '130', + neo_set_output_value_135: '135', + neo_set_output_value_140: '140', + neo_set_output_value_145: '145', + neo_set_output_value_150: '150', + neo_set_output_value_155: '155', + neo_set_output_value_160: '160', + neo_set_output_value_165: '165', + neo_set_output_value_170: '170', + neo_set_output_value_175: '175', + neo_set_output_value_180: '180', + neo_set_output_value_185: '185', + neo_set_output_value_190: '190', + neo_set_output_value_195: '195', + neo_set_output_value_200: '200', + neo_set_output_value_205: '205', + neo_set_output_value_210: '210', + neo_set_output_value_215: '215', + neo_set_output_value_220: '220', + neo_set_output_value_225: '225', + neo_set_output_value_230: '230', + neo_set_output_value_235: '235', + neo_set_output_value_240: '240', + neo_set_output_value_245: '245', + neo_set_output_value_250: '250', + neo_set_output_value_255: '255', + + neo_sensor_in_digital_1: '1st', + neo_sensor_in_digital_2: '2nd', + neo_sensor_in_digital_3: '3rd', + neo_sensor_in_digital_4: '4th', + + neo_color_black: 'black', + neo_color_white: 'white', + neo_color_red: 'red', + neo_color_yellow: 'yellow', + neo_color_green: 'green', + neo_color_blue: 'blue', + + neo_button_1: 'button 1', + neo_button_2: 'button 2', + neo_button_3: 'button 3', + neo_button_4: 'button 4', + + neo_button_on: 'ON', + neo_button_off: 'OFF', + + neo_buzzer_octave_1: '1 octave', + neo_buzzer_octave_2: '2 octave', + neo_buzzer_octave_3: '3 octave', + neo_buzzer_octave_4: '4 octave', + neo_buzzer_octave_5: '5 octave', + neo_buzzer_octave_6: '6 octave', + + neo_buzzer_do: 'Do', + neo_buzzer_do_sharp: 'Do#', + neo_buzzer_re: 'Re', + neo_buzzer_re_sharp: 'Re#', + neo_buzzer_mi: 'Mi', + neo_buzzer_fa: 'Fa', + neo_buzzer_fa_sharp: 'Fa#', + neo_buzzer_sol: 'So', + neo_buzzer_sol_sharp: 'So#', + neo_buzzer_la: 'La', + neo_buzzer_la_sharp: 'La#', + neo_buzzer_ti: 'Si', + + neo_buzzer_whole_note: 'whole note', + neo_buzzer_half_note: 'a half note', + neo_buzzer_quarter_note: 'a quarter note', + neo_buzzer_8th_note: 'a eighth note', + + neo_lcd_image_1: '1', + neo_lcd_image_2: '2', + neo_lcd_image_3: '3', + neo_lcd_image_4: '4', + neo_lcd_image_5: '5', + neo_lcd_image_6: '6', + neo_lcd_image_7: '7', + neo_lcd_image_8: '8', + neo_lcd_image_9: '9', + neo_lcd_image_10: '10', + neo_lcd_image_11: '11', + neo_lcd_image_12: '12', + neo_lcd_image_13: '13', + neo_lcd_image_14: '14', + neo_lcd_image_15: '15', + }, + }, // + }; + } + + getBlocks() { + return { + /** + * 회전모터 + */ + neo_motor_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_motor_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_motor_title', + }, + class: 'neo_motor', + isNotFor: ['neo'], + events: {}, + }, + neo_motor_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_out_l, 1], + [Lang.Blocks.neo_motor_out_r, 2], + [Lang.Blocks.neo_motor_out_lr, 0], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_95, '95'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_85, '85'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_75, '75'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_65, '65'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_55, '55'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_45, '45'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_35, '35'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_25, '25'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_15, '15'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_5, '5'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_motor_speed_n5, '-5'], + [Lang.Blocks.neo_motor_speed_n10, '-10'], + [Lang.Blocks.neo_motor_speed_n15, '-15'], + [Lang.Blocks.neo_motor_speed_n20, '-20'], + [Lang.Blocks.neo_motor_speed_n25, '-25'], + [Lang.Blocks.neo_motor_speed_n30, '-30'], + [Lang.Blocks.neo_motor_speed_n35, '-35'], + [Lang.Blocks.neo_motor_speed_n40, '-40'], + [Lang.Blocks.neo_motor_speed_n45, '-45'], + [Lang.Blocks.neo_motor_speed_n50, '-50'], + [Lang.Blocks.neo_motor_speed_n55, '-55'], + [Lang.Blocks.neo_motor_speed_n60, '-60'], + [Lang.Blocks.neo_motor_speed_n65, '-65'], + [Lang.Blocks.neo_motor_speed_n70, '-70'], + [Lang.Blocks.neo_motor_speed_n75, '-75'], + [Lang.Blocks.neo_motor_speed_n80, '-80'], + [Lang.Blocks.neo_motor_speed_n85, '-85'], + [Lang.Blocks.neo_motor_speed_n90, '-90'], + [Lang.Blocks.neo_motor_speed_n95, '-95'], + [Lang.Blocks.neo_motor_speed_n100, '-100'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_motor_move', + }, + paramsKeyMap: { + DC: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_motor', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const dc = script.getNumberField('DC', script); + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const dc = script.getNumberField('DC', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_motor_move_both: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'neo_arg_motor_speed', + }, + { + type: 'neo_arg_motor_speed', + }, + null, + ], + type: 'neo_motor_move_both', + }, + paramsKeyMap: { + SPEED_L: 0, + SPEED_R: 1, + }, + class: 'neo_motor', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const speedL = script.getNumberValue('SPEED_L', script); + const speedR = script.getNumberValue('SPEED_R', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [speedL, speedR]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_robot_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_robot_direction_f, 1], + [Lang.Blocks.neo_robot_direction_b, 2], + [Lang.Blocks.neo_robot_direction_l, 3], + [Lang.Blocks.neo_robot_direction_r, 4], + [Lang.Blocks.neo_robot_direction_tl, 5], + [Lang.Blocks.neo_robot_direction_tr, 6], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_95, '95'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_85, '85'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_75, '75'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_65, '65'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_55, '55'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_45, '45'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_35, '35'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_25, '25'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_15, '15'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_5, '5'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_robot_move', + }, + paramsKeyMap: { + DIRECTION: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_motor', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const direction = script.getNumberField('DIRECTION', script); + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const direction = script.getNumberField('DIRECTION', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_motor_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_out_l, 1], + [Lang.Blocks.neo_motor_out_r, 2], + [Lang.Blocks.neo_motor_out_lr, 0], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_motor_stop', + }, + paramsKeyMap: { + DC: 0, + }, + class: 'neo_motor', + isNotFor: ['neo'], + func: (sprite, script) => { + const dc = script.getStringValue('DC', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_STOP, [dc]); + return script.callReturn(); + }, + }, + neo_robot_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_robot_stop', + }, + paramsKeyMap: { + // + }, + class: 'neo_motor', + isNotFor: ['neo'], + func: (sprite, script) => { + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP, []); + return script.callReturn(); + }, + }, + /** + * 서보모터 + */ + neo_servo_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_servo_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_servo_title', + }, + class: 'neo_servo', + isNotFor: ['neo'], + events: {}, + }, + neo_servo_reset: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_servo_reset', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_RESET, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_servo_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_servo_angle_360, '360'], + [Lang.Blocks.neo_servo_angle_350, '350'], + [Lang.Blocks.neo_servo_angle_340, '340'], + [Lang.Blocks.neo_servo_angle_330, '330'], + [Lang.Blocks.neo_servo_angle_320, '320'], + [Lang.Blocks.neo_servo_angle_310, '310'], + [Lang.Blocks.neo_servo_angle_300, '300'], + [Lang.Blocks.neo_servo_angle_290, '290'], + [Lang.Blocks.neo_servo_angle_280, '280'], + [Lang.Blocks.neo_servo_angle_270, '270'], + [Lang.Blocks.neo_servo_angle_260, '260'], + [Lang.Blocks.neo_servo_angle_250, '250'], + [Lang.Blocks.neo_servo_angle_240, '240'], + [Lang.Blocks.neo_servo_angle_230, '230'], + [Lang.Blocks.neo_servo_angle_220, '220'], + [Lang.Blocks.neo_servo_angle_210, '210'], + [Lang.Blocks.neo_servo_angle_200, '200'], + [Lang.Blocks.neo_servo_angle_190, '190'], + [Lang.Blocks.neo_servo_angle_180, '180'], + [Lang.Blocks.neo_servo_angle_170, '170'], + [Lang.Blocks.neo_servo_angle_160, '160'], + [Lang.Blocks.neo_servo_angle_150, '150'], + [Lang.Blocks.neo_servo_angle_140, '140'], + [Lang.Blocks.neo_servo_angle_130, '130'], + [Lang.Blocks.neo_servo_angle_120, '120'], + [Lang.Blocks.neo_servo_angle_110, '110'], + [Lang.Blocks.neo_servo_angle_100, '100'], + [Lang.Blocks.neo_servo_angle_90, '90'], + [Lang.Blocks.neo_servo_angle_80, '80'], + [Lang.Blocks.neo_servo_angle_70, '70'], + [Lang.Blocks.neo_servo_angle_60, '60'], + [Lang.Blocks.neo_servo_angle_50, '50'], + [Lang.Blocks.neo_servo_angle_40, '40'], + [Lang.Blocks.neo_servo_angle_30, '30'], + [Lang.Blocks.neo_servo_angle_20, '20'], + [Lang.Blocks.neo_servo_angle_10, '10'], + [Lang.Blocks.neo_servo_angle_0, '0'], + [Lang.Blocks.neo_servo_angle_n10, '-10'], + [Lang.Blocks.neo_servo_angle_n20, '-20'], + [Lang.Blocks.neo_servo_angle_n30, '-30'], + [Lang.Blocks.neo_servo_angle_n40, '-40'], + [Lang.Blocks.neo_servo_angle_n50, '-50'], + [Lang.Blocks.neo_servo_angle_n60, '-60'], + [Lang.Blocks.neo_servo_angle_n70, '-70'], + [Lang.Blocks.neo_servo_angle_n80, '-80'], + [Lang.Blocks.neo_servo_angle_n90, '-90'], + [Lang.Blocks.neo_servo_angle_n100, '-100'], + [Lang.Blocks.neo_servo_angle_n110, '-110'], + [Lang.Blocks.neo_servo_angle_n120, '-120'], + [Lang.Blocks.neo_servo_angle_n130, '-130'], + [Lang.Blocks.neo_servo_angle_n140, '-140'], + [Lang.Blocks.neo_servo_angle_n150, '-150'], + [Lang.Blocks.neo_servo_angle_n160, '-160'], + [Lang.Blocks.neo_servo_angle_n170, '-170'], + [Lang.Blocks.neo_servo_angle_n180, '-180'], + [Lang.Blocks.neo_servo_angle_n190, '-190'], + [Lang.Blocks.neo_servo_angle_n200, '-200'], + [Lang.Blocks.neo_servo_angle_n210, '-210'], + [Lang.Blocks.neo_servo_angle_n220, '-220'], + [Lang.Blocks.neo_servo_angle_n230, '-230'], + [Lang.Blocks.neo_servo_angle_n240, '-240'], + [Lang.Blocks.neo_servo_angle_n250, '-250'], + [Lang.Blocks.neo_servo_angle_n260, '-260'], + [Lang.Blocks.neo_servo_angle_n270, '-270'], + [Lang.Blocks.neo_servo_angle_n280, '-280'], + [Lang.Blocks.neo_servo_angle_n290, '-290'], + [Lang.Blocks.neo_servo_angle_n300, '-300'], + [Lang.Blocks.neo_servo_angle_n310, '-310'], + [Lang.Blocks.neo_servo_angle_n320, '-320'], + [Lang.Blocks.neo_servo_angle_n330, '-330'], + [Lang.Blocks.neo_servo_angle_n340, '-340'], + [Lang.Blocks.neo_servo_angle_n350, '-350'], + [Lang.Blocks.neo_servo_angle_n360, '-360'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_servo_angle', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const angle = script.getStringField('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (angle === 'IN1' || angle === 'IN2' || angle === 'IN3') { + if (speed === 'IN1' || angle === 'IN2' || angle === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } else { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_servo_angle_var: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_arg_servo_angle', + }, + null, + null, + ], + type: 'neo_servo_angle_var', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringField('OUTPUT', script); + const angle = script.getNumberValue('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_servo_angle_wait: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_servo_angle_360, '360'], + [Lang.Blocks.neo_servo_angle_350, '350'], + [Lang.Blocks.neo_servo_angle_340, '340'], + [Lang.Blocks.neo_servo_angle_330, '330'], + [Lang.Blocks.neo_servo_angle_320, '320'], + [Lang.Blocks.neo_servo_angle_310, '310'], + [Lang.Blocks.neo_servo_angle_300, '300'], + [Lang.Blocks.neo_servo_angle_290, '290'], + [Lang.Blocks.neo_servo_angle_280, '280'], + [Lang.Blocks.neo_servo_angle_270, '270'], + [Lang.Blocks.neo_servo_angle_260, '260'], + [Lang.Blocks.neo_servo_angle_250, '250'], + [Lang.Blocks.neo_servo_angle_240, '240'], + [Lang.Blocks.neo_servo_angle_230, '230'], + [Lang.Blocks.neo_servo_angle_220, '220'], + [Lang.Blocks.neo_servo_angle_210, '210'], + [Lang.Blocks.neo_servo_angle_200, '200'], + [Lang.Blocks.neo_servo_angle_190, '190'], + [Lang.Blocks.neo_servo_angle_180, '180'], + [Lang.Blocks.neo_servo_angle_170, '170'], + [Lang.Blocks.neo_servo_angle_160, '160'], + [Lang.Blocks.neo_servo_angle_150, '150'], + [Lang.Blocks.neo_servo_angle_140, '140'], + [Lang.Blocks.neo_servo_angle_130, '130'], + [Lang.Blocks.neo_servo_angle_120, '120'], + [Lang.Blocks.neo_servo_angle_110, '110'], + [Lang.Blocks.neo_servo_angle_100, '100'], + [Lang.Blocks.neo_servo_angle_90, '90'], + [Lang.Blocks.neo_servo_angle_80, '80'], + [Lang.Blocks.neo_servo_angle_70, '70'], + [Lang.Blocks.neo_servo_angle_60, '60'], + [Lang.Blocks.neo_servo_angle_50, '50'], + [Lang.Blocks.neo_servo_angle_40, '40'], + [Lang.Blocks.neo_servo_angle_30, '30'], + [Lang.Blocks.neo_servo_angle_20, '20'], + [Lang.Blocks.neo_servo_angle_10, '10'], + [Lang.Blocks.neo_servo_angle_0, '0'], + [Lang.Blocks.neo_servo_angle_n10, '-10'], + [Lang.Blocks.neo_servo_angle_n20, '-20'], + [Lang.Blocks.neo_servo_angle_n30, '-30'], + [Lang.Blocks.neo_servo_angle_n40, '-40'], + [Lang.Blocks.neo_servo_angle_n50, '-50'], + [Lang.Blocks.neo_servo_angle_n60, '-60'], + [Lang.Blocks.neo_servo_angle_n70, '-70'], + [Lang.Blocks.neo_servo_angle_n80, '-80'], + [Lang.Blocks.neo_servo_angle_n90, '-90'], + [Lang.Blocks.neo_servo_angle_n100, '-100'], + [Lang.Blocks.neo_servo_angle_n110, '-110'], + [Lang.Blocks.neo_servo_angle_n120, '-120'], + [Lang.Blocks.neo_servo_angle_n130, '-130'], + [Lang.Blocks.neo_servo_angle_n140, '-140'], + [Lang.Blocks.neo_servo_angle_n150, '-150'], + [Lang.Blocks.neo_servo_angle_n160, '-160'], + [Lang.Blocks.neo_servo_angle_n170, '-170'], + [Lang.Blocks.neo_servo_angle_n180, '-180'], + [Lang.Blocks.neo_servo_angle_n190, '-190'], + [Lang.Blocks.neo_servo_angle_n200, '-200'], + [Lang.Blocks.neo_servo_angle_n210, '-210'], + [Lang.Blocks.neo_servo_angle_n220, '-220'], + [Lang.Blocks.neo_servo_angle_n230, '-230'], + [Lang.Blocks.neo_servo_angle_n240, '-240'], + [Lang.Blocks.neo_servo_angle_n250, '-250'], + [Lang.Blocks.neo_servo_angle_n260, '-260'], + [Lang.Blocks.neo_servo_angle_n270, '-270'], + [Lang.Blocks.neo_servo_angle_n280, '-280'], + [Lang.Blocks.neo_servo_angle_n290, '-290'], + [Lang.Blocks.neo_servo_angle_n300, '-300'], + [Lang.Blocks.neo_servo_angle_n310, '-310'], + [Lang.Blocks.neo_servo_angle_n320, '-320'], + [Lang.Blocks.neo_servo_angle_n330, '-330'], + [Lang.Blocks.neo_servo_angle_n340, '-340'], + [Lang.Blocks.neo_servo_angle_n350, '-350'], + [Lang.Blocks.neo_servo_angle_n360, '-360'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_servo_angle_wait', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringField('OUTPUT', script); + const angle = script.getStringField('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (angle === 'IN1' || angle === 'IN2' || angle === 'IN3') { + if (speed === 'IN1' || angle === 'IN2' || angle === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [output, angle, speed]); + } else { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [output, angle, speed]); + } + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [output, angle, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_servo_rotate: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_servo_direction_f, 1], + [Lang.Blocks.neo_servo_direction_b, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_servo_rotate', + }, + paramsKeyMap: { + OUTPUT: 0, + DIRECTION: 1, + SPEED: 2, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const direction = script.getStringField('DIRECTION', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ROTATE, [output, direction, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ROTATE, [output, direction, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_servo_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_servo_stop', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_servo', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_STOP, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 라인트레이서 + */ + neo_line_tracer_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_line_tracer_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_line_tracer_title', + }, + class: 'neo_line_tracer', + isNotFor: ['neo'], + events: {}, + }, + neo_line_tracer_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_line_tracer_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_line_tracer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + const duration = script.getStringValue('DURATION', script); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.LINE_TRACER_START, [speed]); + } else { + this.requestCommand(blockId, NeoBlockType.LINE_TRACER_START, [speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_TRACER_START, [0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_line_cross_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_line_cross_move_1, 1], + [Lang.Blocks.neo_line_cross_move_2, 2], + [Lang.Blocks.neo_line_cross_move_3, 3], + [Lang.Blocks.neo_line_cross_move_4, 4], + [Lang.Blocks.neo_line_cross_move_5, 5], + [Lang.Blocks.neo_line_cross_move_6, 6], + [Lang.Blocks.neo_line_cross_move_7, 7], + [Lang.Blocks.neo_line_cross_move_8, 8], + [Lang.Blocks.neo_line_cross_move_9, 9], + [Lang.Blocks.neo_line_cross_move_10, 10], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_line_cross_move', + }, + paramsKeyMap: { + COUNT: 0, + }, + class: 'neo_line_tracer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const count = script.getStringValue('COUNT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_CROSS_MOVE, [count]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_line_cross_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_turn_direction_l, 10], + [Lang.Blocks.neo_turn_direction_r, 11], + [Lang.Blocks.neo_turn_direction_u, 12], + ], + value: 10, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_line_cross_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_line_tracer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const direction = script.getStringValue('DIRECTION', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_CROSS_TURN, [direction]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 자율주행 + */ + neo_auto_driving_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_auto_driving_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_auto_driving_title', + }, + class: 'neo_auto_driving', + isNotFor: ['neo'], + events: {}, + }, + neo_auto_driving_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_auto_driving_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_auto_driving', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [speed]); + } else { + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_auto_driving_sensor_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1_2, 0x10], + [Lang.Blocks.neo_input_11_12, 0x11], + [Lang.Blocks.neo_input_13_14, 0x12], + [Lang.Blocks.neo_input_21_22, 0x13], + [Lang.Blocks.neo_input_23_24, 0x14], + ], + value: 0x10, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_auto_driving_sensor_start', + }, + paramsKeyMap: { + SENSOR: 0, + SPEED: 1, + }, + class: 'neo_auto_driving', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const sensor = script.getNumberField('SENSOR', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.AUTO_DRIVING_SENSOR_START, [sensor, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_SENSOR_START, [sensor, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_auto_driving_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_auto_driving_stop', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_auto_driving', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 자율주차 + */ + neo_auto_parking_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_auto_parking_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_auto_parking_title', + }, + class: 'neo_auto_parking', + isNotFor: ['neo'], + events: {}, + }, + neo_auto_parking_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_auto_parking_which_l, 1], + [Lang.Blocks.neo_auto_parking_which_r, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_auto_parking_direction_b, 1], + [Lang.Blocks.neo_auto_parking_direction_s, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_auto_parking_start', + }, + paramsKeyMap: { + WHICH: 0, + DIRECTION: 1, + }, + class: 'neo_auto_parking', + isNotFor: ['neo'], + func: async (sprite, script) => { + const direction = script.getNumberValue('DIRECTION', script); + if (direction === 1) { + return this.runAutoParkingBackward(script); + } else { + return this.runAutoParkingSide(script); + } + }, + }, + /** + * 차선변경 + */ + neo_line_change_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_line_change_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_line_change_title', + }, + class: 'neo_line_change', + isNotFor: ['neo'], + events: {}, + }, + neo_line_change_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_line_change_direction_l, 2], + [Lang.Blocks.neo_line_change_direction_r, 3], + ], + value: 2, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_line_change_start', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_line_change', + isNotFor: ['neo'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + neo_line_change_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_turn_direction_l, 4], + [Lang.Blocks.neo_turn_direction_r, 5], + [Lang.Blocks.neo_turn_direction_u, 6], + ], + value: 4, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_line_change_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_line_change', + isNotFor: ['neo'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + /** + * 골목주행 + */ + neo_auto_detect_wall_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_auto_detect_wall_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_auto_detect_wall_title', + }, + class: 'neo_auto_detect_wall', + isNotFor: ['neo'], + events: {}, + }, + neo_auto_detect_wall_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_auto_detect_wall_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_auto_detect_wall', + isNotFor: ['neo'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + neo_auto_detect_wall_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_turn_direction_l, 2], + [Lang.Blocks.neo_turn_direction_r, 3], + [Lang.Blocks.neo_turn_direction_u, 4], + ], + value: 2, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_auto_detect_wall_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_auto_detect_wall', + isNotFor: ['neo'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + /** + * LED + */ + neo_led_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_led_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_led_title', + }, + class: 'neo_led', + isNotFor: ['neo'], + events: {}, + }, + neo_led_on: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_led_brightness_100, '100'], + [Lang.Blocks.neo_led_brightness_90, '90'], + [Lang.Blocks.neo_led_brightness_80, '80'], + [Lang.Blocks.neo_led_brightness_70, '70'], + [Lang.Blocks.neo_led_brightness_60, '60'], + [Lang.Blocks.neo_led_brightness_50, '50'], + [Lang.Blocks.neo_led_brightness_40, '40'], + [Lang.Blocks.neo_led_brightness_30, '30'], + [Lang.Blocks.neo_led_brightness_20, '20'], + [Lang.Blocks.neo_led_brightness_10, '10'], + [Lang.Blocks.neo_led_brightness_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_led_on', + }, + paramsKeyMap: { + OUTPUT: 0, + BRIGHTNESS: 1, + DURATION: 2, + }, + class: 'neo_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const brightness = script.getStringValue('BRIGHTNESS', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (brightness.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.LED_ON, [output, brightness]); + } else { + this.requestCommand(blockId, NeoBlockType.LED_ON, [output, brightness]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_ON, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_led_blink: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_led_blink_speed_1, 500], + [Lang.Blocks.neo_led_blink_speed_2, 400], + [Lang.Blocks.neo_led_blink_speed_3, 300], + [Lang.Blocks.neo_led_blink_speed_4, 200], + [Lang.Blocks.neo_led_blink_speed_5, 100], + ], + value: 500, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_led_blink', + }, + paramsKeyMap: { + OUTPUT: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const speed = script.getStringValue('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.LED_BLINK, [output, speed, 100]); + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_BLINK, [output, 0, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_led_off: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_led_off', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_OFF, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 컬러 LED + */ + neo_color_led_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_color_led_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_color_led_title', + }, + class: 'neo_color_led', + isNotFor: ['neo'], + events: {}, + }, + neo_color_led_on: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Color', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_color_led_on', + }, + paramsKeyMap: { + OUTPUT: 0, + COLOR: 1, + DURATION: 2, + }, + class: 'neo_color_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const color = script.getStringValue('COLOR', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.COLOR_LED_ON, [output, color]); + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.COLOR_LED_ON, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_color_led_off: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_color_led_off', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_color_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.COLOR_LED_OFF, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_color_led_on_with_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_color_led_on_with_sensor', + }, + paramsKeyMap: { + INPUT: 0, + OUTPUT: 1, + }, + class: 'neo_color_led', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const input = script.getStringValue('INPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestExtCommand(blockId, NeoBlockType.COLOR_LED_ON_SENSOR, [output, input]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 출력 + */ + neo_set_output_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_set_output_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_set_output_title', + }, + class: 'neo_set_output', + isNotFor: ['neo'], + events: {}, + }, + neo_set_output: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + [Lang.Blocks.neo_output_12, 'OUT12'], + [Lang.Blocks.neo_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_set_output_value_255, '255'], + [Lang.Blocks.neo_set_output_value_250, '250'], + [Lang.Blocks.neo_set_output_value_245, '245'], + [Lang.Blocks.neo_set_output_value_240, '240'], + [Lang.Blocks.neo_set_output_value_235, '235'], + [Lang.Blocks.neo_set_output_value_230, '230'], + [Lang.Blocks.neo_set_output_value_225, '225'], + [Lang.Blocks.neo_set_output_value_220, '220'], + [Lang.Blocks.neo_set_output_value_215, '215'], + [Lang.Blocks.neo_set_output_value_210, '210'], + [Lang.Blocks.neo_set_output_value_205, '205'], + [Lang.Blocks.neo_set_output_value_200, '200'], + [Lang.Blocks.neo_set_output_value_195, '195'], + [Lang.Blocks.neo_set_output_value_190, '190'], + [Lang.Blocks.neo_set_output_value_185, '185'], + [Lang.Blocks.neo_set_output_value_180, '180'], + [Lang.Blocks.neo_set_output_value_175, '175'], + [Lang.Blocks.neo_set_output_value_170, '170'], + [Lang.Blocks.neo_set_output_value_165, '165'], + [Lang.Blocks.neo_set_output_value_160, '160'], + [Lang.Blocks.neo_set_output_value_155, '155'], + [Lang.Blocks.neo_set_output_value_150, '150'], + [Lang.Blocks.neo_set_output_value_145, '145'], + [Lang.Blocks.neo_set_output_value_140, '140'], + [Lang.Blocks.neo_set_output_value_135, '135'], + [Lang.Blocks.neo_set_output_value_130, '130'], + [Lang.Blocks.neo_set_output_value_125, '125'], + [Lang.Blocks.neo_set_output_value_120, '120'], + [Lang.Blocks.neo_set_output_value_115, '115'], + [Lang.Blocks.neo_set_output_value_110, '110'], + [Lang.Blocks.neo_set_output_value_105, '105'], + [Lang.Blocks.neo_set_output_value_100, '100'], + [Lang.Blocks.neo_set_output_value_95, '95'], + [Lang.Blocks.neo_set_output_value_90, '90'], + [Lang.Blocks.neo_set_output_value_85, '85'], + [Lang.Blocks.neo_set_output_value_80, '80'], + [Lang.Blocks.neo_set_output_value_75, '75'], + [Lang.Blocks.neo_set_output_value_70, '70'], + [Lang.Blocks.neo_set_output_value_65, '65'], + [Lang.Blocks.neo_set_output_value_60, '60'], + [Lang.Blocks.neo_set_output_value_55, '55'], + [Lang.Blocks.neo_set_output_value_50, '50'], + [Lang.Blocks.neo_set_output_value_45, '45'], + [Lang.Blocks.neo_set_output_value_40, '40'], + [Lang.Blocks.neo_set_output_value_35, '35'], + [Lang.Blocks.neo_set_output_value_30, '30'], + [Lang.Blocks.neo_set_output_value_25, '25'], + [Lang.Blocks.neo_set_output_value_20, '20'], + [Lang.Blocks.neo_set_output_value_15, '15'], + [Lang.Blocks.neo_set_output_value_10, '10'], + [Lang.Blocks.neo_set_output_value_5, '5'], + [Lang.Blocks.neo_set_output_value_0, '0'], + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_arg_duration', + }, + null, + ], + type: 'neo_set_output', + }, + paramsKeyMap: { + OUTPUT: 0, + VALUE: 1, + DURATION: 2, + }, + class: 'neo_set_output', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const value = script.getStringValue('VALUE', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (value.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.SET_OUTPUT, [output, value]); + } else { + this.requestCommand(blockId, NeoBlockType.SET_OUTPUT, [output, value]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SET_OUTPUT, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 센서 + */ + neo_sensor_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_sensor_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_sensor_title', + }, + class: 'neo_sensor', + isNotFor: ['neo'], + events: {}, + }, + neo_sensor_in: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_sensor_in', + }, + paramsKeyMap: { + INPUT: 0, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = Entry.hw.portData['sensor']; + switch (input) { + case 'IN1': + return sensorData['in1Values'][0]; + case 'IN2': + return sensorData['in2Values'][0]; + case 'IN3': + return sensorData['in3Values'][0]; + } + return 0; + }, + }, + neo_sensor_digital_in: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_sensor_in_digital_1, 0], + [Lang.Blocks.neo_sensor_in_digital_2, 1], + [Lang.Blocks.neo_sensor_in_digital_3, 2], + [Lang.Blocks.neo_sensor_in_digital_4, 3], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_sensor_digital_in', + }, + paramsKeyMap: { + INPUT: 0, + INDEX: 1, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const index = script.getNumberField('INDEX'); + const sensorData = Entry.hw.portData['sensor']; + switch (input) { + case 'IN1': + return sensorData['in1Values'][index]; + case 'IN2': + return sensorData['in2Values'][index]; + case 'IN3': + return sensorData['in3Values'][index]; + } + return 0; + }, + }, + neo_sensor_convert: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['10'], + }, + { + type: 'number', + params: ['255'], + }, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['100'], + }, + ], + type: 'neo_sensor_convert', + }, + paramsKeyMap: { + INPUT: 0, + FROM_MIN: 1, + FROM_MAX: 2, + TO_MIN: 3, + TO_MAX: 4, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = Entry.hw.portData['sensor']; + let value = 0; + switch (input) { + case 'IN1': + value = sensorData['in1Values'][0]; + break; + case 'IN2': + value = sensorData['in2Values'][0]; + break; + case 'IN3': + value = sensorData['in3Values'][0]; + break; + } + let fromMin = script.getNumberValue('FROM_MIN', script); + let fromMax = script.getNumberValue('FROM_MAX', script); + let toMin = script.getNumberValue('TO_MIN', script); + let toMax = script.getNumberValue('TO_MAX', script); + + if (fromMin > fromMax) { + const temp = fromMin; + fromMin = fromMax; + fromMax = temp; + } + + if (toMin > toMax) { + const temp = toMin; + toMin = toMax; + toMax = temp; + } + + value -= fromMin; + value = value * ((toMax - toMin) / (fromMax - fromMin)); + value += toMin; + value = Math.min(toMax, value); + value = Math.max(toMin, value); + + return Math.round(value); + }, + }, + neo_sensor_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + [Lang.Blocks.neo_input_12, 'IN12'], + [Lang.Blocks.neo_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_compare_gt, '>='], + [Lang.Blocks.neo_compare_g, '>'], + [Lang.Blocks.neo_compare_e, '='], + [Lang.Blocks.neo_compare_l, '<'], + [Lang.Blocks.neo_compare_lt, '<='], + ], + value: '>', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [null, null, 10], + type: 'neo_sensor_compare', + }, + paramsKeyMap: { + INPUT: 0, + SYMBOL: 1, + VALUE: 2, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = Entry.hw.portData['sensor']; + const symbol = script.getStringField('SYMBOL'); + const value = Entry.parseNumber(script.getStringValue('VALUE')); + + if (input === 'IN12') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + if (symbol === '=') { + return sensor1 === value && sensor2 === value; + } else if (symbol === '>') { + return sensor1 > value && sensor2 > value; + } else if (symbol === '<') { + return sensor1 < value && sensor2 < value; + } else if (symbol === '>=') { + return sensor1 >= value && sensor2 >= value; + } else if (symbol === '<=') { + return sensor1 <= value && sensor2 <= value; + } + } else if (input === 'IN123') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + const sensor3 = sensorData['in3Values'][0]; + if (symbol === '=') { + return sensor1 === value && sensor2 === value && sensor3 === value; + } else if (symbol === '>') { + return sensor1 > value && sensor2 > value && sensor3 > value; + } else if (symbol === '<') { + return sensor1 < value && sensor2 < value && sensor3 < value; + } else if (symbol === '>=') { + return sensor1 >= value && sensor2 >= value && sensor3 >= value; + } else if (symbol === '<=') { + return sensor1 <= value && sensor2 <= value && sensor3 <= value; + } + } else { + let sensorValue = 0; + switch (input) { + case 'IN1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'IN2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'IN3': + sensorValue = sensorData['in3Values'][0]; + break; + } + if (symbol === '=') { + return sensorValue === value; + } else if (symbol === '>') { + return sensorValue > value; + } else if (symbol === '<') { + return sensorValue < value; + } else if (symbol === '>=') { + return sensorValue >= value; + } else if (symbol === '<=') { + return sensorValue <= value; + } + } + return false; + }, + }, + neo_sensor_between: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_compare_gt, '>='], + [Lang.Blocks.neo_compare_g, '>'], + [Lang.Blocks.neo_compare_e, '='], + [Lang.Blocks.neo_compare_l, '<'], + [Lang.Blocks.neo_compare_lt, '<='], + ], + value: '<', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + [Lang.Blocks.neo_input_12, 'IN12'], + [Lang.Blocks.neo_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_compare_gt, '>='], + [Lang.Blocks.neo_compare_g, '>'], + [Lang.Blocks.neo_compare_e, '='], + [Lang.Blocks.neo_compare_l, '<'], + [Lang.Blocks.neo_compare_lt, '<='], + ], + value: '<', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [10, null, null, null, 30], + type: 'neo_sensor_between', + }, + paramsKeyMap: { + L_VALUE: 0, + L_SYMBOL: 1, + INPUT: 2, + R_SYMBOL: 3, + R_VALUE: 4, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = Entry.hw.portData['sensor']; + const lSymbol = script.getStringField('L_SYMBOL'); + const lValue = Entry.parseNumber(script.getStringValue('L_VALUE')); + const rSymbol = script.getStringField('R_SYMBOL'); + const rValue = Entry.parseNumber(script.getStringValue('R_VALUE')); + + if (input === 'IN12') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensor1 && lValue === sensor2; + } else if (lSymbol === '>') { + lResult = lValue > sensor1 && lValue > sensor2; + } else if (lSymbol === '<') { + lResult = lValue < sensor1 && lValue < sensor2; + } else if (lSymbol === '>=') { + lResult = lValue >= sensor1 && lValue >= sensor2; + } else if (lSymbol === '<=') { + lResult = lValue <= sensor1 && lValue <= sensor2; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensor1 === rValue && sensor2 === rValue; + } else if (rSymbol === '>') { + rResult = sensor1 > rValue && sensor2 > rValue; + } else if (rSymbol === '<') { + rResult = sensor1 < rValue && sensor2 < rValue; + } else if (rSymbol === '>=') { + rResult = sensor1 >= rValue && sensor2 >= rValue; + } else if (rSymbol === '<=') { + rResult = sensor1 <= rValue && sensor2 <= rValue; + } + return lResult && rResult; + } else if (input === 'IN123') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + const sensor3 = sensorData['in3Values'][0]; + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensor1 && lValue === sensor2 && lValue === sensor3; + } else if (lSymbol === '>') { + lResult = lValue > sensor1 && lValue > sensor2 && lValue > sensor3; + } else if (lSymbol === '<') { + lResult = lValue < sensor1 && lValue < sensor2 && lValue < sensor3; + } else if (lSymbol === '>=') { + lResult = lValue >= sensor1 && lValue >= sensor2 && lValue >= sensor3; + } else if (lSymbol === '<=') { + lResult = lValue <= sensor1 && lValue <= sensor2 && lValue <= sensor3; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensor1 === rValue && sensor2 === rValue && sensor3 === rValue; + } else if (rSymbol === '>') { + rResult = sensor1 > rValue && sensor2 > rValue && sensor3 > rValue; + } else if (rSymbol === '<') { + rResult = sensor1 < rValue && sensor2 < rValue && sensor3 < rValue; + } else if (rSymbol === '>=') { + rResult = sensor1 >= rValue && sensor2 >= rValue && sensor3 >= rValue; + } else if (rSymbol === '<=') { + rResult = sensor1 <= rValue && sensor2 <= rValue && sensor3 <= rValue; + } + return lResult && rResult; + } else { + let sensorValue = 0; + switch (input) { + case 'IN1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'IN2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'IN3': + sensorValue = sensorData['in3Values'][0]; + break; + } + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensorValue; + } else if (lSymbol === '>') { + lResult = lValue > sensorValue; + } else if (lSymbol === '<') { + lResult = lValue < sensorValue; + } else if (lSymbol === '>=') { + lResult = lValue >= sensorValue; + } else if (lSymbol === '<=') { + lResult = lValue <= sensorValue; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensorValue === rValue; + } else if (rSymbol === '>') { + rResult = sensorValue > rValue; + } else if (rSymbol === '<') { + rResult = sensorValue < rValue; + } else if (rSymbol === '>=') { + rResult = sensorValue >= rValue; + } else if (rSymbol === '<=') { + rResult = sensorValue <= rValue; + } + return lResult && rResult; + } + }, + }, + neo_sensor_color_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + [Lang.Blocks.neo_input_12, 'IN12'], + [Lang.Blocks.neo_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_color_black, 1], + [Lang.Blocks.neo_color_white, 2], + [Lang.Blocks.neo_color_red, 3], + [Lang.Blocks.neo_color_yellow, 4], + [Lang.Blocks.neo_color_green, 5], + [Lang.Blocks.neo_color_blue, 6], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_sensor_color_compare', + }, + paramsKeyMap: { + INPUT: 0, + COLOR: 1, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = Entry.hw.portData['sensor']; + const color = script.getNumberField('COLOR'); + let sensorValue = 0; + switch (input) { + case 'in1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'in2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'in3': + sensorValue = sensorData['in3Values'][0]; + break; + } + + if (color === 1) { + return sensorValue === 0; + } else if (color === 2) { + return sensorValue === 0; + } else if (color === 3) { + return sensorValue === 0; + } else if (color === 4) { + return sensorValue === 0; + } else if (color === 5) { + return sensorValue === 0; + } else if (color === 6) { + return sensorValue === 0; + } + return false; + }, + }, + neo_sensor_button_pressed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#FFFFFF', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_button_1, '1'], + [Lang.Blocks.neo_button_2, '2'], + [Lang.Blocks.neo_button_3, '3'], + [Lang.Blocks.neo_button_4, '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_button_on, 'ON'], + [Lang.Blocks.neo_button_off, 'OFF'], + ], + value: 'on', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_sensor_button_pressed', + }, + paramsKeyMap: { + BUTTON: 0, + PRESSED: 1, + }, + class: 'neo_sensor', + isNotFor: ['neo'], + func: (sprite, script) => { + const button = script.getNumberField('BUTTON'); + const pressed = script.getStringField('PRESSED'); + const sensorData = Entry.hw.portData['sensor']; + const value = sensorData['IR']; + if (button === 1) { + if (pressed === 'ON') return value === 10; + else return value !== 10; + } else if (button === 2) { + if (pressed === 'ON') return value === 11; + else return value !== 11; + } else if (button === 3) { + if (pressed === 'ON') return value === 12; + else return value !== 12; + } else if (button === 4) { + if (pressed === 'ON') return value === 13; + else return value !== 13; + } + }, + }, + /** + * 버저 + */ + neo_buzzer_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_buzzer_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_buzzer_title', + }, + class: 'neo_buzzer', + isNotFor: ['neo'], + events: {}, + }, + neo_buzzer_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_buzzer_octave_1, '0'], + [Lang.Blocks.neo_buzzer_octave_2, '1'], + [Lang.Blocks.neo_buzzer_octave_3, '2'], + [Lang.Blocks.neo_buzzer_octave_4, '3'], + [Lang.Blocks.neo_buzzer_octave_5, '4'], + [Lang.Blocks.neo_buzzer_octave_6, '5'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_buzzer_do, '1'], + [Lang.Blocks.neo_buzzer_do_sharp, '2'], + [Lang.Blocks.neo_buzzer_re, '3'], + [Lang.Blocks.neo_buzzer_re_sharp, '4'], + [Lang.Blocks.neo_buzzer_mi, '5'], + [Lang.Blocks.neo_buzzer_fa, '6'], + [Lang.Blocks.neo_buzzer_fa_sharp, '7'], + [Lang.Blocks.neo_buzzer_sol, '8'], + [Lang.Blocks.neo_buzzer_sol_sharp, '9'], + [Lang.Blocks.neo_buzzer_la, '10'], + [Lang.Blocks.neo_buzzer_la_sharp, '11'], + [Lang.Blocks.neo_buzzer_ti, '12'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_buzzer_whole_note, '1'], + [Lang.Blocks.neo_buzzer_half_note, '2'], + [Lang.Blocks.neo_buzzer_quarter_note, '4'], + [Lang.Blocks.neo_buzzer_8th_note, '8'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_buzzer_start', + }, + paramsKeyMap: { + OCTAVE: 0, + NOTE: 1, + DURATION: 2, + }, + class: 'neo_buzzer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + const octave = script.getNumberField('OCTAVE', script); + const note = script.getNumberField('NOTE', script); + const value = Math.min(note + 12 * octave, 72); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.BUZZER_START, [value]); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, (1 / duration) * 2000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.BUZZER_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_buzzer_with_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_input_1, 'IN1'], + [Lang.Blocks.neo_input_2, 'IN2'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_buzzer_with_sensor', + }, + paramsKeyMap: { + INPUT: 0, + }, + class: 'neo_buzzer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const input = script.getStringValue('INPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestExtCommand(blockId, NeoBlockType.BUZZER_WITH_SENSOR, [input]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_buzzer_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_buzzer_stop', + }, + paramsKeyMap: {}, + class: 'neo_buzzer', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.BUZZER_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * LCD + */ + neo_lcd_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lcd_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lcd_title', + }, + class: 'neo_lcd', + isNotFor: ['neo'], + events: {}, + }, + neo_lcd_image: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lcd_image_1, '1'], + [Lang.Blocks.neo_lcd_image_2, '2'], + [Lang.Blocks.neo_lcd_image_3, '3'], + [Lang.Blocks.neo_lcd_image_4, '4'], + [Lang.Blocks.neo_lcd_image_5, '5'], + [Lang.Blocks.neo_lcd_image_6, '6'], + [Lang.Blocks.neo_lcd_image_7, '7'], + [Lang.Blocks.neo_lcd_image_8, '8'], + [Lang.Blocks.neo_lcd_image_9, '9'], + [Lang.Blocks.neo_lcd_image_10, '10'], + [Lang.Blocks.neo_lcd_image_11, '11'], + [Lang.Blocks.neo_lcd_image_12, '12'], + [Lang.Blocks.neo_lcd_image_13, '13'], + [Lang.Blocks.neo_lcd_image_14, '14'], + [Lang.Blocks.neo_lcd_image_15, '15'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_lcd_image', + }, + paramsKeyMap: { + OUTPUT: 0, + IMAGE: 1, + }, + class: 'neo_lcd', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const image = script.getStringValue('IMAGE', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LCD_IMAGE, [output, image]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_lcd_text: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_output_1, 'OUT1'], + [Lang.Blocks.neo_output_2, 'OUT2'], + [Lang.Blocks.neo_output_3, 'OUT3'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, 'NEO', null], + type: 'neo_lcd_text', + }, + paramsKeyMap: { + OUTPUT: 0, + TEXT: 1, + }, + class: 'neo_lcd', + isNotFor: ['neo'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const text = script.getStringValue('TEXT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LCD_TEXT, [output, text]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * ARG Blocks + */ + neo_arg_motor_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_motor_speed_n10, '-10'], + [Lang.Blocks.neo_motor_speed_n20, '-20'], + [Lang.Blocks.neo_motor_speed_n30, '-30'], + [Lang.Blocks.neo_motor_speed_n40, '-40'], + [Lang.Blocks.neo_motor_speed_n50, '-50'], + [Lang.Blocks.neo_motor_speed_n60, '-60'], + [Lang.Blocks.neo_motor_speed_n70, '-70'], + [Lang.Blocks.neo_motor_speed_n80, '-80'], + [Lang.Blocks.neo_motor_speed_n90, '-90'], + [Lang.Blocks.neo_motor_speed_n100, '-100'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_duration: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_duration_c, 'c'], + [Lang.Blocks.neo_duration_0, '0'], + [Lang.Blocks.neo_duration_1, '1'], + [Lang.Blocks.neo_duration_2, '2'], + [Lang.Blocks.neo_duration_3, '3'], + [Lang.Blocks.neo_duration_4, '4'], + [Lang.Blocks.neo_duration_5, '5'], + [Lang.Blocks.neo_duration_6, '6'], + [Lang.Blocks.neo_duration_7, '7'], + [Lang.Blocks.neo_duration_8, '8'], + [Lang.Blocks.neo_duration_9, '9'], + ], + value: 'c', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_robot_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_servo_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_servo_angle_360, '360'], + [Lang.Blocks.neo_servo_angle_350, '350'], + [Lang.Blocks.neo_servo_angle_340, '340'], + [Lang.Blocks.neo_servo_angle_330, '330'], + [Lang.Blocks.neo_servo_angle_320, '320'], + [Lang.Blocks.neo_servo_angle_310, '310'], + [Lang.Blocks.neo_servo_angle_300, '300'], + [Lang.Blocks.neo_servo_angle_290, '290'], + [Lang.Blocks.neo_servo_angle_280, '280'], + [Lang.Blocks.neo_servo_angle_270, '270'], + [Lang.Blocks.neo_servo_angle_260, '260'], + [Lang.Blocks.neo_servo_angle_250, '250'], + [Lang.Blocks.neo_servo_angle_240, '240'], + [Lang.Blocks.neo_servo_angle_230, '230'], + [Lang.Blocks.neo_servo_angle_220, '220'], + [Lang.Blocks.neo_servo_angle_210, '210'], + [Lang.Blocks.neo_servo_angle_200, '200'], + [Lang.Blocks.neo_servo_angle_190, '190'], + [Lang.Blocks.neo_servo_angle_180, '180'], + [Lang.Blocks.neo_servo_angle_170, '170'], + [Lang.Blocks.neo_servo_angle_160, '160'], + [Lang.Blocks.neo_servo_angle_150, '150'], + [Lang.Blocks.neo_servo_angle_140, '140'], + [Lang.Blocks.neo_servo_angle_130, '130'], + [Lang.Blocks.neo_servo_angle_120, '120'], + [Lang.Blocks.neo_servo_angle_110, '110'], + [Lang.Blocks.neo_servo_angle_100, '100'], + [Lang.Blocks.neo_servo_angle_90, '90'], + [Lang.Blocks.neo_servo_angle_80, '80'], + [Lang.Blocks.neo_servo_angle_70, '70'], + [Lang.Blocks.neo_servo_angle_60, '60'], + [Lang.Blocks.neo_servo_angle_50, '50'], + [Lang.Blocks.neo_servo_angle_40, '40'], + [Lang.Blocks.neo_servo_angle_30, '30'], + [Lang.Blocks.neo_servo_angle_20, '20'], + [Lang.Blocks.neo_servo_angle_10, '10'], + [Lang.Blocks.neo_servo_angle_0, '0'], + [Lang.Blocks.neo_servo_angle_n10, '-10'], + [Lang.Blocks.neo_servo_angle_n20, '-20'], + [Lang.Blocks.neo_servo_angle_n30, '-30'], + [Lang.Blocks.neo_servo_angle_n40, '-40'], + [Lang.Blocks.neo_servo_angle_n50, '-50'], + [Lang.Blocks.neo_servo_angle_n60, '-60'], + [Lang.Blocks.neo_servo_angle_n70, '-70'], + [Lang.Blocks.neo_servo_angle_n80, '-80'], + [Lang.Blocks.neo_servo_angle_n90, '-90'], + [Lang.Blocks.neo_servo_angle_n100, '-100'], + [Lang.Blocks.neo_servo_angle_n110, '-110'], + [Lang.Blocks.neo_servo_angle_n120, '-120'], + [Lang.Blocks.neo_servo_angle_n130, '-130'], + [Lang.Blocks.neo_servo_angle_n140, '-140'], + [Lang.Blocks.neo_servo_angle_n150, '-150'], + [Lang.Blocks.neo_servo_angle_n160, '-160'], + [Lang.Blocks.neo_servo_angle_n170, '-170'], + [Lang.Blocks.neo_servo_angle_n180, '-180'], + [Lang.Blocks.neo_servo_angle_n190, '-190'], + [Lang.Blocks.neo_servo_angle_n200, '-200'], + [Lang.Blocks.neo_servo_angle_n210, '-210'], + [Lang.Blocks.neo_servo_angle_n220, '-220'], + [Lang.Blocks.neo_servo_angle_n230, '-230'], + [Lang.Blocks.neo_servo_angle_n240, '-240'], + [Lang.Blocks.neo_servo_angle_n250, '-250'], + [Lang.Blocks.neo_servo_angle_n260, '-260'], + [Lang.Blocks.neo_servo_angle_n270, '-270'], + [Lang.Blocks.neo_servo_angle_n280, '-280'], + [Lang.Blocks.neo_servo_angle_n290, '-290'], + [Lang.Blocks.neo_servo_angle_n300, '-300'], + [Lang.Blocks.neo_servo_angle_n310, '-310'], + [Lang.Blocks.neo_servo_angle_n320, '-320'], + [Lang.Blocks.neo_servo_angle_n330, '-330'], + [Lang.Blocks.neo_servo_angle_n340, '-340'], + [Lang.Blocks.neo_servo_angle_n350, '-350'], + [Lang.Blocks.neo_servo_angle_n360, '-360'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_servo_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_auto_driving_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_motor_speed_100, '100'], + [Lang.Blocks.neo_motor_speed_90, '90'], + [Lang.Blocks.neo_motor_speed_80, '80'], + [Lang.Blocks.neo_motor_speed_70, '70'], + [Lang.Blocks.neo_motor_speed_60, '60'], + [Lang.Blocks.neo_motor_speed_50, '50'], + [Lang.Blocks.neo_motor_speed_40, '40'], + [Lang.Blocks.neo_motor_speed_30, '30'], + [Lang.Blocks.neo_motor_speed_20, '20'], + [Lang.Blocks.neo_motor_speed_10, '10'], + [Lang.Blocks.neo_motor_speed_0, '0'], + [Lang.Blocks.neo_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_led_brightness: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_led_brightness_100, '100'], + [Lang.Blocks.neo_led_brightness_90, '90'], + [Lang.Blocks.neo_led_brightness_80, '80'], + [Lang.Blocks.neo_led_brightness_70, '70'], + [Lang.Blocks.neo_led_brightness_60, '60'], + [Lang.Blocks.neo_led_brightness_50, '50'], + [Lang.Blocks.neo_led_brightness_40, '40'], + [Lang.Blocks.neo_led_brightness_30, '30'], + [Lang.Blocks.neo_led_brightness_20, '20'], + [Lang.Blocks.neo_led_brightness_10, '10'], + [Lang.Blocks.neo_led_brightness_0, '0'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_led_blink_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_led_blink_speed_1, '1'], + [Lang.Blocks.neo_led_blink_speed_2, '2'], + [Lang.Blocks.neo_led_blink_speed_3, '3'], + [Lang.Blocks.neo_led_blink_speed_4, '4'], + [Lang.Blocks.neo_led_blink_speed_5, '5'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_arg_set_output_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_set_output_value_255, '255'], + [Lang.Blocks.neo_set_output_value_250, '250'], + [Lang.Blocks.neo_set_output_value_245, '245'], + [Lang.Blocks.neo_set_output_value_240, '240'], + [Lang.Blocks.neo_set_output_value_235, '235'], + [Lang.Blocks.neo_set_output_value_230, '230'], + [Lang.Blocks.neo_set_output_value_225, '225'], + [Lang.Blocks.neo_set_output_value_220, '220'], + [Lang.Blocks.neo_set_output_value_215, '215'], + [Lang.Blocks.neo_set_output_value_210, '210'], + [Lang.Blocks.neo_set_output_value_205, '205'], + [Lang.Blocks.neo_set_output_value_200, '200'], + [Lang.Blocks.neo_set_output_value_195, '195'], + [Lang.Blocks.neo_set_output_value_190, '190'], + [Lang.Blocks.neo_set_output_value_185, '185'], + [Lang.Blocks.neo_set_output_value_180, '180'], + [Lang.Blocks.neo_set_output_value_175, '175'], + [Lang.Blocks.neo_set_output_value_170, '170'], + [Lang.Blocks.neo_set_output_value_165, '165'], + [Lang.Blocks.neo_set_output_value_160, '160'], + [Lang.Blocks.neo_set_output_value_155, '155'], + [Lang.Blocks.neo_set_output_value_150, '150'], + [Lang.Blocks.neo_set_output_value_145, '145'], + [Lang.Blocks.neo_set_output_value_140, '140'], + [Lang.Blocks.neo_set_output_value_135, '135'], + [Lang.Blocks.neo_set_output_value_130, '130'], + [Lang.Blocks.neo_set_output_value_125, '125'], + [Lang.Blocks.neo_set_output_value_120, '120'], + [Lang.Blocks.neo_set_output_value_115, '115'], + [Lang.Blocks.neo_set_output_value_110, '110'], + [Lang.Blocks.neo_set_output_value_105, '105'], + [Lang.Blocks.neo_set_output_value_100, '100'], + [Lang.Blocks.neo_set_output_value_95, '95'], + [Lang.Blocks.neo_set_output_value_90, '90'], + [Lang.Blocks.neo_set_output_value_85, '85'], + [Lang.Blocks.neo_set_output_value_80, '80'], + [Lang.Blocks.neo_set_output_value_75, '75'], + [Lang.Blocks.neo_set_output_value_70, '70'], + [Lang.Blocks.neo_set_output_value_65, '65'], + [Lang.Blocks.neo_set_output_value_60, '60'], + [Lang.Blocks.neo_set_output_value_55, '55'], + [Lang.Blocks.neo_set_output_value_50, '50'], + [Lang.Blocks.neo_set_output_value_45, '45'], + [Lang.Blocks.neo_set_output_value_40, '40'], + [Lang.Blocks.neo_set_output_value_35, '35'], + [Lang.Blocks.neo_set_output_value_30, '30'], + [Lang.Blocks.neo_set_output_value_25, '25'], + [Lang.Blocks.neo_set_output_value_20, '20'], + [Lang.Blocks.neo_set_output_value_15, '15'], + [Lang.Blocks.neo_set_output_value_10, '10'], + [Lang.Blocks.neo_set_output_value_5, '5'], + [Lang.Blocks.neo_set_output_value_0, '0'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_arg', + isNotFor: ['neo'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + }; + } + + getCheckSum(command) { + let checkSum = 0; + for (let i = 0; i < command.length; i++) { + checkSum += command[i]; + } + return checkSum & 255; + } + + getUnitId(port) { + switch (port) { + case 'OUT1': + return UnitId.CONTROLLER_OUT1; + case 'OUT2': + return UnitId.CONTROLLER_OUT2; + case 'OUT3': + return UnitId.CONTROLLER_OUT3; + case 'OUT12': + return UnitId.CONTROLLER_OUT12; + case 'OUT123': + return UnitId.CONTROLLER_OUT_ALL; + case 'IN1': + return UnitId.CONTROLLER_IN1; + case 'IN2': + return UnitId.CONTROLLER_IN2; + case 'IN3': + return UnitId.CONTROLLER_IN3; + } + return UnitId.CONTROLLER; + } + + makePdu(command) { + const pdu = []; + pdu.push(...HEADER); + pdu.push(command.length); + pdu.push(...command); + pdu.push(this.getCheckSum(command)); + return pdu; + } + + requestCommand(blockId, type, params) { + console.log(blockId + ' requested'); + if (this.pendingResponseList[blockId]) { + delete this.pendingResponseList[blockId]; + } + this.pendingResponseList[blockId] = 'executed'; + const command = this.makeCommand(blockId, type, params); + if (!command) return; + const pdu = this.makePdu(command); + this.executeList[blockId] = { + blockId, + pdu, + }; + Entry.hw.sendQueue.executeList = { ...this.executeList }; + Entry.hw.update(); + } + + requestExtCommand(blockId, type, params) { + console.log(blockId + ' requested'); + if (this.pendingResponseList[blockId]) { + delete this.pendingResponseList[blockId]; + } + this.pendingResponseList[blockId] = 'executed'; + const command = this.makeCommandExt(blockId, type, params); + if (!command) return; + const pdu = this.makePdu(command); + this.executeList[blockId] = { + blockId, + pdu, + }; + Entry.hw.sendQueue.executeList = { ...this.executeList }; + Entry.hw.update(); + } + + makeCommand(blockId, type, params) { + //const body = [FrameCode.BASIC, PduCode.ACTION_COMMAND, PduType.REQUEST]; + const body = [FrameCode.BASIC, PduCode.BASIC, blockId]; + if (type === NeoBlockType.MOTOR_MOVE) { + const which = params[0]; + const speed = Math.abs(params[1]); + const direction = params[1] < 0 ? 1 : 0; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(which, 2); + data.writeInt16LE(direction, 4); + body.push(...data); + } else if (type === NeoBlockType.MOTOR_MOVE_BOTH) { + const speedL = params[0]; + const speedR = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR_BOTH); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speedL, 0); + data.writeInt16LE(speedR, 2); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_MOVE) { + const robotCommand = params[0]; + const speed = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(robotCommand, 2); + body.push(...data); + } else if (type === NeoBlockType.MOTOR_STOP || type === NeoBlockType.AUTO_DRIVING_STOP) { + const which = params[0]; + const direction = 1; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + data.writeInt16LE(which, 2); + data.writeInt16LE(direction, 4); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_STOP) { + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SERVO_RESET) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.RESET); + const data = Buffer.from([0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE) { + const output = params[0]; + const angle = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ANGLE); + const data = Buffer.from([0, 0, 0, 0, 1, 0]); + data.writeInt16LE(angle, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE_WAIT) { + const output = params[0]; + const angle = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ANGLE_WAIT); + const data = Buffer.from([0, 0, 0, 0, 1, 0]); + data.writeInt16LE(angle, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ROTATE) { + const output = params[0]; + const direction = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ROTATE); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_STOP) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.STOP); + } else if ( + type === NeoBlockType.LINE_TRACER_START || + type === NeoBlockType.AUTO_DRIVING_START || + type === NeoBlockType.AUTO_DETECT_WALL_START + ) { + const speed = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0x10, 0]); + data.writeInt16LE(speed, 0); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DRIVING_SENSOR_START) { + const sensor = params[0]; + const speed = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(sensor, 2); + body.push(...data); + } else if (type === NeoBlockType.LINE_CROSS_MOVE) { + const count = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.LINE_TRACER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(count, 0); + body.push(...data); + } else if (type === NeoBlockType.LINE_CROSS_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.LINE_TRACER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(direction, 0); + body.push(...data); + } else if (type === NeoBlockType.AUTO_PARKING_START) { + // TODO : which 누락 + const which = params[0]; + const direction = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_PARKING); + const data = Buffer.from([0, 0]); + data.writeInt16LE(direction, 0); + body.push(...data); + } else if (type === NeoBlockType.LINE_CHANGE_START) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DRIVING); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.LINE_CHANGE_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DRIVING); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DETECT_WALL_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DETECT_WALL); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_ON) { + const output = params[0]; + const brightness = params[1]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(brightness, 0); + body.push(...data); + } else if (type === NeoBlockType.LED_BLINK) { + const output = params[0]; + const speed = params[1]; + const brightness = params[2]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(brightness, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_OFF) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_ON) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.COLOR_LED, LedCommand.ON); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + const color = params[1]; + if (color.length === 7 && color[0] === '#') { + const r = color.substr(1, 2); + const g = color.substr(3, 2); + const b = color.substr(5, 2); + data.writeInt16LE(parseInt(r, 16), 0); + data.writeInt16LE(parseInt(g, 16), 2); + data.writeInt16LE(parseInt(b, 16), 4); + } + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_OFF) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.COLOR_LED, LedCommand.OFF); + } else if (type === NeoBlockType.SET_OUTPUT) { + const output = params[0]; + const value = params[1]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(value, 0); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_START) { + const value = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(value, 0); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_STOP) { + const value = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + body.push(...data); + } else if (type === NeoBlockType.LCD_IMAGE) { + const output = this.getUnitId(params[0]); + const value = params[1]; + body.push(output, ActorKind.LCD, LcdCommand.IMAGE); + const data = Buffer.from([value, 0]); + body.push(...data); + } else if (type === NeoBlockType.LCD_TEXT) { + const output = this.getUnitId(params[0]); + const value = params[1]; + body.push(output, ActorKind.LCD, LcdCommand.TEXT); + body.push(0); // 글씨크기 : 지금 안됨. + if (value.length > 0) { + for (let idx = 0; idx < value.length; idx++) { + body.push(value.charCodeAt(idx)); + } + } + } + return body; + } + + makeCommandExt(blockId, type, params) { + const body = [FrameCode.BASIC]; + if (type === NeoBlockType.MOTOR_MOVE) { + const which = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([unitId, 0, which, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_MOVE) { + const robotCommand = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([unitId, 0, 0, 0]); + data.writeInt16LE(robotCommand, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE || type === NeoBlockType.SERVO_ANGLE_WAIT) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + const speed = params[2]; + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.SERVO, ServoCommand.ANGLE); + const data = Buffer.from([inUnitId, 0, 0, 0, 1, 0]); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ROTATE) { + const unitId = this.getUnitId(params[0]); + const direction = params[1]; + const inUnitId = this.getUnitId(params[2]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.SERVO, ServoCommand.ROTATE); + const data = Buffer.from([inUnitId, 0, 0, 0]); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if ( + type === NeoBlockType.LINE_TRACER_START || + type === NeoBlockType.AUTO_DRIVING_START || + type === NeoBlockType.AUTO_DETECT_WALL_START + ) { + const unitId = this.getUnitId(params[0]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([unitId, 0, 0x10, 0]); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DRIVING_SENSOR_START) { + const sensor = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(unitId, 0); + data.writeInt16LE(sensor, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_ON) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.LED, 0); + const data = Buffer.from([inUnitId, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SET_OUTPUT) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.LED, 0); + const data = Buffer.from([inUnitId, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_WITH_SENSOR) { + const sensorUnitId = this.getUnitId(params[0]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(sensorUnitId, 0); + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_ON_SENSOR) { + const outUnitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_3, blockId, outUnitId, ActorKind.COLOR_LED, LedCommand.ON); + const data = Buffer.from([inUnitId, 1, inUnitId, 2, inUnitId, 3]); + body.push(...data); + } + return body; + } + + /* + 후면주차 실행 (pending response 하지 않고 바로 다음 단계로 넘어감 : phase 가 너무 많아서 간소화) + 주석은 왼쪽 기준으로 오른쪽에서는 좌우만 바꿔준다. + */ + runAutoParkingBackward(script) { + const which = script.getNumberValue('WHICH', script); + const sensorData = Entry.hw.portData['sensor']; + console.log(script.exec_phase); + if (!script.exec_phase) { + // 1. 로봇 제자리 오른쪽 20% + script.exec_phase = '2_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 6 : 5, 20]); + setTimeout(() => { + script.exec_phase = '3_robot_stop'; + }, 3500); + } else if (script.exec_phase === '2_wait') { + // 2. 3.5초 기다리기 + } else if (script.exec_phase === '3_robot_stop') { + // 3. 로봇 정지 + script.exec_phase = '4_robot_rotate'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } else if (script.exec_phase === '4_robot_rotate') { + // 4. 로봇 제자리 왼쪽 20% + script.exec_phase = '5_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 5 : 6, 20]); + } else if (script.exec_phase === '5_wait_sensor') { + // 5. IN2 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in2Values[0] : sensorData.in1Values[0]; + if (compareValue > 40) { + script.exec_phase = '6_stop_robot'; + } + } else if (script.exec_phase === '6_stop_robot') { + // 6. 로봇 멈추기 + script.exec_phase = '7_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '8_robot_back'; + }, 1000); + } else if (script.exec_phase === '7_wait') { + // 7. 1초 기다리기 + } else if (script.exec_phase === '8_robot_back') { + // 8. 로봇 후진 20% + script.exec_phase = '9_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + } else if (script.exec_phase === '9_wait_sensor') { + // 9. IN1 20초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 20) { + script.exec_phase = '10_stop_robot'; + } + } else if (script.exec_phase === '10_stop_robot') { + // 10. 로봇 멈추기 + script.exec_phase = '11_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '12_adjustment'; + }, 1000); + } else if (script.exec_phase === '11_wait') { + // 11. 1초 기다리기 + } else if (script.exec_phase === '12_adjustment') { + // 12. IN2 가 IN1 보다 크면 [-20, 0] 아니면 [0, -20] , IN2 가 60보다 크면 break : 차체 조정시에는 좌우 구분 없음 + if (sensorData.in2Values[0] > sensorData.in1Values[0]) { + if (script.adjust_direction !== 'left') { + script.adjust_direction = 'left'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [-20, 0]); + } + } else { + if (script.adjust_direction !== 'right') { + script.adjust_direction = 'right'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [0, -20]); + } + } + if (sensorData.in2Values[0] >= 60) { + script.exec_phase = '13_stop_robot'; + } + } else if (script.exec_phase === '13_stop_robot') { + // 13. 로봇 멈추기 + script.exec_phase = '14_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '15_robot_back'; + }, 1000); + } else if (script.exec_phase === '14_wait') { + // 14. 1초 기다리기 + } else if (script.exec_phase === '15_robot_back') { + // 15. 로봇 후진 20% + script.exec_phase = '16_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + setTimeout(() => { + script.exec_phase = '17_stop_robot'; + }, 2000); + } else if (script.exec_phase === '16_wait') { + // 16. 2초 기다리기 + } else if (script.exec_phase === '17_stop_robot') { + // 17. 로봇 멈추기 + script.exec_phase = 'end'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } + // + else if (script.exec_phase === 'end') { + // 종료 + return script.callReturn(); + } + + return script; + } + + runAutoParkingSide(script) { + const which = script.getNumberValue('WHICH', script); + const sensorData = Entry.hw.portData['sensor']; + console.log(script.exec_phase); + if (!script.exec_phase) { + // 1. 로봇 오른쪽 30% + script.exec_phase = '2_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 4 : 3, 30]); + setTimeout(() => { + script.exec_phase = '3_robot_stop'; + }, 2500); + } else if (script.exec_phase === '2_wait') { + // 2. 2초 기다리기 + } else if (script.exec_phase === '3_robot_stop') { + // 3. 로봇 정지 + script.exec_phase = '4_robot_back'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } else if (script.exec_phase === '4_robot_back') { + // 4. 로봇 뒤로 30% + script.exec_phase = '5_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 30]); + } else if (script.exec_phase === '5_wait_sensor') { + // 5. IN1 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 40) { + script.exec_phase = '6_wait_sensor'; + } + } else if (script.exec_phase === '6_wait_sensor') { + // 6. IN2 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in2Values[0] : sensorData.in1Values[0]; + if (compareValue > 40) { + script.exec_phase = '7_robot_stop'; + } + } else if (script.exec_phase === '7_robot_stop') { + // 7. 로봇 멈추기 + script.exec_phase = '8_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '9_robot_rotate'; + }, 1000); + } else if (script.exec_phase === '8_wait') { + // 8. 1초 기다리기 + } else if (script.exec_phase === '9_robot_rotate') { + // 9. 로봇 제자리왼쪽 20% + script.exec_phase = '10_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 5 : 6, 20]); + } else if (script.exec_phase === '10_wait_sensor') { + // 10. IN1 40초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 40) { + script.exec_phase = '11_stop_robot'; + } + } else if (script.exec_phase === '11_stop_robot') { + // 11. 로봇 멈추기 + script.exec_phase = '12_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '13_adjustment'; + }, 1000); + } else if (script.exec_phase === '12_wait') { + // 12. 1초 기다리기 + } else if (script.exec_phase === '13_adjustment') { + // 13. 라인트레이서 + script.exec_phase = '14_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [7, 20]); + setTimeout(() => { + script.exec_phase = '15_robot_stop'; + }, 1500); + } else if (script.exec_phase === '14_wait') { + // 14. 1.5초 기다리기 + } else if (script.exec_phase === '15_robot_stop') { + // 15. 로봇 멈추기 + script.exec_phase = '16_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '17_robot_back'; + }, 1000); + } else if (script.exec_phase === '16_wait') { + // 16. 1초 기다리기 + } else if (script.exec_phase === '17_robot_back') { + // 17. 로봇 후진 20% + script.exec_phase = '18_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + setTimeout(() => { + script.exec_phase = '19_stop_robot'; + }, 1000); + } else if (script.exec_phase === '18_wait') { + // 18. 1초 기다리기 + } else if (script.exec_phase === '19_stop_robot') { + // 19. 로봇 멈추기 + script.exec_phase = 'end'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } + // + else if (script.exec_phase === 'end') { + // 종료 + return script.callReturn(); + } + + return script; + } +})(); + +module.exports = Entry.Neo; diff --git a/src/playground/blocks/hardware/block_roborobo_robokit_rs.js b/src/playground/blocks/hardware/block_roborobo_robokit_rs.js index 5366dad99a..46692c00a5 100644 --- a/src/playground/blocks/hardware/block_roborobo_robokit_rs.js +++ b/src/playground/blocks/hardware/block_roborobo_robokit_rs.js @@ -103,6 +103,7 @@ class RobokitRS extends ArduinoBase { robokit_rs_menu_pin: '%1', robokit_rs_menu_digital_value: '%1', robokit_rs_menu_motor_number: '%1', + robokit_rs_menu_dotmatrix_row: '%1', robokit_rs_set_digital: '%1 번 핀 디지털 값을 %2 (으)로 정하기 %3', robokit_rs_set_motor: '%1 번 모터를 속도 %2 (으)로 %3 %4', @@ -163,6 +164,7 @@ class RobokitRS extends ArduinoBase { robokit_rs_mecanumwheels_state_ccw: '시계 반대 방향 회전', robokit_rs_mecanumwheels_state_stop: '정지', + robokit_rs_dotmatrix_example_all: '모두', robokit_rs_dotmatrix_example_eighth_note: '8분 음표', robokit_rs_dotmatrix_example_sixteenth_note: '16분 음표', robokit_rs_dotmatrix_example_square: '네모', @@ -250,6 +252,7 @@ class RobokitRS extends ArduinoBase { robokit_rs_menu_pin: '%1', robokit_rs_menu_digital_value: '%1', robokit_rs_menu_motor_number: '%1', + robokit_rs_menu_dotmatrix_row: '%1', robokit_rs_set_digital: 'set pin %1 digital value to %2 %3', robokit_rs_set_motor: 'set motor %1 speed to %2 %3 %4', @@ -310,6 +313,7 @@ class RobokitRS extends ArduinoBase { robokit_rs_mecanumwheels_state_ccw: 'rotate counterclockwise', robokit_rs_mecanumwheels_state_stop: 'stop', + robokit_rs_dotmatrix_example_all: 'all', robokit_rs_dotmatrix_example_eighth_note: 'eighth note', robokit_rs_dotmatrix_example_sixteenth_note: 'sixteenth note', robokit_rs_dotmatrix_example_square: 'square', @@ -572,6 +576,40 @@ class RobokitRS extends ArduinoBase { return script.getStringField('NUM'); }, }, + robokit_rs_menu_dotmatrix_row: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['0', '0'], + ['1', '1'], + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + Y: 0, + }, + func: (sprite, script) => { + return script.getStringField('Y'); + }, + }, robokit_rs_set_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, @@ -585,6 +623,7 @@ class RobokitRS extends ArduinoBase { { type: 'Block', accept: 'string', + defualtType: 'number', }, { type: 'Indicator', @@ -1036,20 +1075,9 @@ class RobokitRS extends ArduinoBase { statements: [], params: [ { - type: 'Dropdown', - options: [ - ['0', '0'], - ['1', '1'], - ['2', '2'], - ['3', '3'], - ['4', '4'], - ['5', '5'], - ['6', '6'], - ], - value: '0', - fontSize: 11, - bgColor: EntryStatic.colorSet.block.darken.HARDWARE, - arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + type: 'Block', + accept: 'string', + defualtType: 'number', }, { type: 'Block', @@ -1135,7 +1163,9 @@ class RobokitRS extends ArduinoBase { events: {}, def: { params: [ - null, + { + type: 'robokit_rs_menu_dotmatrix_row' + }, { type: 'number', params: ['0'], @@ -1218,6 +1248,7 @@ class RobokitRS extends ArduinoBase { { type: 'Dropdown', options: [ + [Lang.Blocks.robokit_rs_dotmatrix_example_all, '111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], [Lang.Blocks.robokit_rs_dotmatrix_example_eighth_note, '000000000000000000000011000000000000010100000000000010100000000001110100000000011110000000000001100000000'], [Lang.Blocks.robokit_rs_dotmatrix_example_sixteenth_note, '000000001111000000000011001000000000010001000000000010011000000001110111000000011110111000000001100000000'], [Lang.Blocks.robokit_rs_dotmatrix_example_square, '000111111111000000111111111000000110000011000000110000011000000110000011000000111111111000000111111111000'], @@ -1281,7 +1312,7 @@ class RobokitRS extends ArduinoBase { ['←', '000000000000000000000100000000000001000000000000011111110000000001000000000000000100000000000000000000000'], ['↖', '000011110000000000011000000000000010100000000000010010000000000000001000000000000000100000000000000010000'], ], - value: '000000000000000000000011000000000000010100000000000010100000000001110100000000011110000000000001100000000', + value: '111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, @@ -2068,6 +2099,8 @@ class RobokitRS extends ArduinoBase { set_dotmatrix_row (sprite, script) { const y = script.getNumberValue('Y'); + if (y < 0 || y > 6) return script.callReturn(); + let dots = ''; for (let i = 0; i < 16; i++) { const value = script.getNumberValue('X' + i); diff --git a/src/playground/blocks/hardwareLite/block_choco_lite.js b/src/playground/blocks/hardwareLite/block_choco_lite.js new file mode 100644 index 0000000000..5783b32579 --- /dev/null +++ b/src/playground/blocks/hardwareLite/block_choco_lite.js @@ -0,0 +1,1941 @@ +'use strict'; +const Buffer = require('buffer').Buffer; + +(function() { + Entry.ChocoLite = new (class ChocoLite { + constructor() { + this.id = '45.1'; + this.name = 'ChocoLite'; + this.url = 'http://jjomulrak.com'; + this.imageName = 'chocolite.png'; + this.title = { + ko: '쪼코', + en: 'Choco', + }; + this.duration = 32; + this.blockMenuBlocks = [ + 'chocolite_move_forward', + 'chocolite_move_backward', + 'chocolite_turn_left', + 'chocolite_turn_right', + 'chocolite_move_right_left', + 'chocolite_onoff_led_rear', + 'chocolite_set_led_color', + 'chocolite_play_sound', + 'chocolite_is_front_sensor', + 'chocolite_is_bottom_sensor', + 'chocolite_is_light_sensor', + 'chocolite_get_front_sensor', + 'chocolite_get_bottom_sensor', + 'chocolite_get_light_sensor', + ]; + this.portData = { + baudRate: 115200, + dataBits: 8, + parity: 'none', + stopBits: 1, + bufferSize: 512, + constantServing: true, + connectionType: 'bytestream', + }; + + // prettier-ignore + this.crctab16 = new Uint16Array([ + 0X0000, 0X1189, 0X2312, 0X329B, 0X4624, 0X57AD, 0X6536, 0X74BF, + 0X8C48, 0X9DC1, 0XAF5A, 0XBED3, 0XCA6C, 0XDBE5, 0XE97E, 0XF8F7, + 0X1081, 0X0108, 0X3393, 0X221A, 0X56A5, 0X472C, 0X75B7, 0X643E, + 0X9CC9, 0X8D40, 0XBFDB, 0XAE52, 0XDAED, 0XCB64, 0XF9FF, 0XE876, + 0X2102, 0X308B, 0X0210, 0X1399, 0X6726, 0X76AF, 0X4434, 0X55BD, + 0XAD4A, 0XBCC3, 0X8E58, 0X9FD1, 0XEB6E, 0XFAE7, 0XC87C, 0XD9F5, + 0X3183, 0X200A, 0X1291, 0X0318, 0X77A7, 0X662E, 0X54B5, 0X453C, + 0XBDCB, 0XAC42, 0X9ED9, 0X8F50, 0XFBEF, 0XEA66, 0XD8FD, 0XC974, + 0X4204, 0X538D, 0X6116, 0X709F, 0X0420, 0X15A9, 0X2732, 0X36BB, + 0XCE4C, 0XDFC5, 0XED5E, 0XFCD7, 0X8868, 0X99E1, 0XAB7A, 0XBAF3, + 0X5285, 0X430C, 0X7197, 0X601E, 0X14A1, 0X0528, 0X37B3, 0X263A, + 0XDECD, 0XCF44, 0XFDDF, 0XEC56, 0X98E9, 0X8960, 0XBBFB, 0XAA72, + 0X6306, 0X728F, 0X4014, 0X519D, 0X2522, 0X34AB, 0X0630, 0X17B9, + 0XEF4E, 0XFEC7, 0XCC5C, 0XDDD5, 0XA96A, 0XB8E3, 0X8A78, 0X9BF1, + 0X7387, 0X620E, 0X5095, 0X411C, 0X35A3, 0X242A, 0X16B1, 0X0738, + 0XFFCF, 0XEE46, 0XDCDD, 0XCD54, 0XB9EB, 0XA862, 0X9AF9, 0X8B70, + 0X8408, 0X9581, 0XA71A, 0XB693, 0XC22C, 0XD3A5, 0XE13E, 0XF0B7, + 0X0840, 0X19C9, 0X2B52, 0X3ADB, 0X4E64, 0X5FED, 0X6D76, 0X7CFF, + 0X9489, 0X8500, 0XB79B, 0XA612, 0XD2AD, 0XC324, 0XF1BF, 0XE036, + 0X18C1, 0X0948, 0X3BD3, 0X2A5A, 0X5EE5, 0X4F6C, 0X7DF7, 0X6C7E, + 0XA50A, 0XB483, 0X8618, 0X9791, 0XE32E, 0XF2A7, 0XC03C, 0XD1B5, + 0X2942, 0X38CB, 0X0A50, 0X1BD9, 0X6F66, 0X7EEF, 0X4C74, 0X5DFD, + 0XB58B, 0XA402, 0X9699, 0X8710, 0XF3AF, 0XE226, 0XD0BD, 0XC134, + 0X39C3, 0X284A, 0X1AD1, 0X0B58, 0X7FE7, 0X6E6E, 0X5CF5, 0X4D7C, + 0XC60C, 0XD785, 0XE51E, 0XF497, 0X8028, 0X91A1, 0XA33A, 0XB2B3, + 0X4A44, 0X5BCD, 0X6956, 0X78DF, 0X0C60, 0X1DE9, 0X2F72, 0X3EFB, + 0XD68D, 0XC704, 0XF59F, 0XE416, 0X90A9, 0X8120, 0XB3BB, 0XA232, + 0X5AC5, 0X4B4C, 0X79D7, 0X685E, 0X1CE1, 0X0D68, 0X3FF3, 0X2E7A, + 0XE70E, 0XF687, 0XC41C, 0XD595, 0XA12A, 0XB0A3, 0X8238, 0X93B1, + 0X6B46, 0X7ACF, 0X4854, 0X59DD, 0X2D62, 0X3CEB, 0X0E70, 0X1FF9, + 0XF78F, 0XE606, 0XD49D, 0XC514, 0XB1AB, 0XA022, 0X92B9, 0X8330, + 0X7BC7, 0X6A4E, 0X58D5, 0X495C, 0X3DE3, 0X2C6A, 0X1EF1, 0X0F78, + ]); + + this.SEND_PACKET = { + START: 0x7c, + END: 0x7e, + }; + + this.cmdSeq = 0; + this.isSendInitData = 'none'; + + this.sendBuffers = []; + this.recvBuffers = []; + this.executeCmd = { + processing: 'none', + cb: null, + }; + + this.sensorData = { + is_front_sensor: false, + is_bottom_sensor: false, + is_light_sensor: false, + front_sensor: 0, + bottom_sensor: 0, + light_sensor: 0, + }; + + this.sensorInit = { + inited: 'none', + sensor0: { + min: 0, + max: 0, + threshold: 0, + }, + sensor1: { + min: 0, + max: 0, + threshold: 0, + }, + sensor2: { + min: 0, + max: 0, + threshold: 0, + }, + }; + + this.ledStatus = [0, 0, 0]; //right, left, rear + + this.setZero(); + } + + // get monitorTemplate() { + // return { + // imgPath: 'hw_lite/choco2.png', + // width: 256, + // height: 256, + // listPorts: { + // '2': { + // name: `${Lang.Hw.port_en} 2 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '3': { + // name: `${Lang.Hw.port_en} 3 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '4': { + // name: `${Lang.Hw.port_en} 4 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '5': { + // name: `${Lang.Hw.port_en} 5 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '6': { + // name: `${Lang.Hw.port_en} 6 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '7': { + // name: `${Lang.Hw.port_en} 7 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '8': { + // name: `${Lang.Hw.port_en} 8 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '9': { + // name: `${Lang.Hw.port_en} 9 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '10': { + // name: `${Lang.Hw.port_en} 10 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '11': { + // name: `${Lang.Hw.port_en} 11 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '12': { + // name: `${Lang.Hw.port_en} 12 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // '13': { + // name: `${Lang.Hw.port_en} 13 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a0: { + // name: `${Lang.Hw.port_en} A0 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a1: { + // name: `${Lang.Hw.port_en} A1 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a2: { + // name: `${Lang.Hw.port_en} A2 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a3: { + // name: `${Lang.Hw.port_en} A3 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a4: { + // name: `${Lang.Hw.port_en} A4 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // a5: { + // name: `${Lang.Hw.port_en} A5 ${Lang.Hw.port_ko}`, + // type: 'input', + // pos: { x: 0, y: 0 }, + // }, + // }, + // mode: 'both', + // }; + // } + + // getMonitorPort() { + // return { + // //TODO : 통신때마다 모니터되는 포트 업데이트 하기위해 현재 포트값들 리턴 + // } + // } + + setZero() { + this.cmdSeq = 0; + this.isSendInitData = 'none'; + + this.sendBuffers = []; + this.recvBuffers = []; + this.executeCmd = { + processing: 'none', + cb: null, + }; + + this.sensorData = { + is_front_sensor: false, + is_bottom_sensor: false, + is_light_sensor: false, + front_sensor: 0, + bottom_sensor: 0, + light_sensor: 0, + }; + + this.sensorInit = { + inited: 'none', + sensor0: { + min: 0, + max: 0, + threshold: 0, + }, + sensor1: { + min: 0, + max: 0, + threshold: 0, + }, + sensor2: { + min: 0, + max: 0, + threshold: 0, + }, + }; + + if (Entry.hwLite) { + Entry.hwLite.update(); + } + } + + _addRecvData(value) { + let parsed = false; + let startIdx = 0; + this.recvBuffers = this.recvBuffers.concat(...value); + for (let i = 0; i < this.recvBuffers.length; i++) { + if (this.recvBuffers[i] === this.SEND_PACKET.END) { + if (this.recvBuffers[0] === this.SEND_PACKET.START) { + this._parseRecvData(this.recvBuffers.slice(startIdx, i + 1)); + this.recvBuffers.splice(0, i + 1); + parsed = true; + break; + } + this.recvBuffers.splice(0, i + 1); + startIdx = i; + } + } + return parsed; + } + + _parseRecvData(data) { + if (data.length > 12 && data[0] === this.SEND_PACKET.START) { + const idx = data.indexOf(this.SEND_PACKET.END); + if (idx > 0) { + const decodedData = this.escapeEecode(data.slice(1, idx)); + + const command = decodedData.readUInt8(0); + const seqNo = decodedData.readUInt8(1); + const sensor0 = decodedData.readUInt16LE(2); + const sensor1 = decodedData.readUInt16LE(4); + const sensor2 = decodedData.readUInt16LE(6); + + this.sensorData.front_sensor = sensor0; + this.sensorData.bottom_sensor = sensor1; + this.sensorData.light_sensor = sensor2; + + if (decodedData.length === 29) { + this.sensorInit.inited = 'inited'; + this.sensorInit.sensor0.min = decodedData.readUInt16LE(9); + this.sensorInit.sensor0.max = decodedData.readUInt16LE(11); + this.sensorInit.sensor0.threshold = decodedData.readUInt16LE(13); + this.sensorInit.sensor1.min = decodedData.readUInt16LE(15); + this.sensorInit.sensor1.max = decodedData.readUInt16LE(17); + this.sensorInit.sensor1.threshold = decodedData.readUInt16LE(19); + this.sensorInit.sensor2.min = decodedData.readUInt16LE(21); + this.sensorInit.sensor2.max = decodedData.readUInt16LE(23); + this.sensorInit.sensor2.threshold = decodedData.readUInt16LE(25); + + // console.log( + // `Sensor inited`, + // `${this.sensorInit.sensor0.min},`, + // `${this.sensorInit.sensor0.max},`, + // `${this.sensorInit.sensor0.threshold}` + // ); + } + if (this.sensorInit.inited === 'inited') { + if (this.sensorData.front_sensor < this.sensorInit.sensor0.min) { + this.sensorData.front_sensor = this.sensorInit.sensor0.min; + } + if (this.sensorData.front_sensor > this.sensorInit.sensor0.max) { + this.sensorData.front_sensor = this.sensorInit.sensor0.max; + } + if (this.sensorData.bottom_sensor < this.sensorInit.sensor1.min) { + this.sensorData.bottom_sensor = this.sensorInit.sensor1.min; + } + if (this.sensorData.bottom_sensor > this.sensorInit.sensor1.max) { + this.sensorData.bottom_sensor = this.sensorInit.sensor1.max; + } + if (this.sensorData.light_sensor < this.sensorInit.sensor2.min) { + this.sensorData.light_sensor = this.sensorInit.sensor2.min; + } + if (this.sensorData.light_sensor > this.sensorInit.sensor2.max) { + this.sensorData.light_sensor = this.sensorInit.sensor2.max; + } + this.sensorData.is_front_sensor = + this.sensorData.front_sensor < this.sensorInit.sensor0.threshold; + this.sensorData.is_bottom_sensor = + this.sensorData.bottom_sensor > this.sensorInit.sensor1.threshold; + this.sensorData.is_light_sensor = + this.sensorData.light_sensor < this.sensorInit.sensor2.threshold; + + let fVal = this.sensorData.front_sensor; + const fMin = this.sensorInit.sensor0.min; + const fMmax = this.sensorInit.sensor0.max; + fVal = ((fVal - fMin) * 100) / (fMmax - fMin); + + let bVal = this.sensorData.bottom_sensor; + const bMin = this.sensorInit.sensor1.min; + const bMmax = this.sensorInit.sensor1.max; + bVal = ((bVal - bMin) * 100) / (bMmax - bMin); + + let lVal = this.sensorData.light_sensor; + const lMin = this.sensorInit.sensor2.min; + const lMmax = this.sensorInit.sensor2.max; + lVal = ((lVal - lMin) * 100) / (lMmax - lMin); + + this.sensorData.front_sensor = parseInt(fVal, 10); + if (this.sensorData.front_sensor < 0) { + this.sensorData.front_sensor = 0; + } else if (this.sensorData.front_sensor > 100) { + this.sensorData.front_sensor = 100; + } + this.sensorData.bottom_sensor = parseInt(bVal, 10); + if (this.sensorData.bottom_sensor < 0) { + this.sensorData.bottom_sensor = 0; + } else if (this.sensorData.bottom_sensor > 100) { + this.sensorData.bottom_sensor = 100; + } + this.sensorData.light_sensor = parseInt(lVal, 10); + if (this.sensorData.light_sensor < 0) { + this.sensorData.light_sensor = 0; + } else if (this.sensorData.light_sensor > 100) { + this.sensorData.light_sensor = 100; + } + } + + // console.log( + // `command:${command}, len: ${decodedData.length}`, + // `data:${data.toString('hex')}, seqNo:${seqNo}`, + // `${sensor0},${sensor1},${sensor2}`, + // `${this.sensorData.is_front_sensor},`, + // `${this.sensorData.is_bottom_sensor},`, + // `${this.sensorData.is_light_sensor}`, + // `${this.sensorData.front_sensor},`, + // `${this.sensorData.bottom_sensor},`, + // `${this.sensorData.light_sensor}` + // ); + if (command === 0x02 && this.executeCmd.processing === 'started') { + this.executeCmd.processing = 'done'; + if (this.executeCmd.cb) { + this.executeCmd.cb(); + this.executeCmd.cb = null; + } + } + + if (this.isSendInitData === 'sent') { + this.isSendInitData = 'inited'; + } + } + } + } + + // 디바이스에서 값을 읽어온다. + handleLocalData(data) { + this._addRecvData(data); + } + + //디바이스에 값을 쓴다. + requestLocalData() { + if (this.executeCmd.processing === 'none' || this.executeCmd.processing === 'done') { + if (this.sendBuffers.length > 0) { + const cmd = this.sendBuffers.shift(); + + this.executeCmd.cb = cmd.cb; + this.executeCmd.processing = 'started'; + return cmd.sendData; + } + } + + return null; + } + + async initialHandshake() { + this.recvBuffers = []; + const cmdReady = this.makeData({ + type: 'ready', + }); + this.sensorInit.inited = 'sent'; + // this.sensorInit.inited 가 inited 될 때까지 기다린다. + while (this.sensorInit.inited === 'sent') { + //parsed되었는데 상태가 변경안되면.. 다시 요청을 보낸다. + this.log('Send Data:ready'); + await Entry.hwLite.sendAsync(cmdReady, false, (value) => { + this._addRecvData(value); + }); + } + + this.recvBuffers = []; + const cmdPing = this.makeData({ + type: 'ping2', + }); + this.ledStatus = [0, 0, 0]; + this.isSendInitData = 'sent'; + await Entry.hwLite.sendAsync(cmdPing); + + while (this.isSendInitData === 'sent') { + // this.isSendInitData 가 inited 될 때까지 기다린다. + this.log('Send Data:ping2'); + await Entry.hwLite.sendAsync(cmdPing, false, (value) => { + this._addRecvData(value); + }); + } + return true; + } + + setLanguage() { + return { + ko: { + template: { + chocolite_move_forward: '앞으로 %1 %2 이동 %3', + chocolite_move_backward: '뒤로 %1 %2 이동 %3', + chocolite_turn_left: '왼쪽으로 %1 %2 돌기 %3', + chocolite_turn_right: '오른쪽으로 %1 %2 돌기 %3', + chocolite_move_right_left: '오른쪽으로 %1 왼쪽으로 %2 %3 이동 %4', + chocolite_onoff_led_rear: '뒤쪽 LED %1 %2', + chocolite_set_led_color: '%1 LED %2 %3', + chocolite_play_sound: '%1 소리내기 %2', + chocolite_is_front_sensor: '전방센서', + chocolite_is_bottom_sensor: '바닥센서', + chocolite_is_light_sensor: '빛센서', + chocolite_get_front_sensor: '전방센서', + chocolite_get_bottom_sensor: '바닥센서', + chocolite_get_light_sensor: '빛센서', + }, + Blocks: { + chocolite_move_step: '칸', + chocolite_move_cm: 'cm', + chocolite_trun_drgree: '도', + chocolite_trun_round: '바퀴', + chocolite_toggle_on: '켜기', + chocolite_toggle_off: '끄기', + chocolite_direction_right: '오른쪽', + chocolite_direction_left: '왼쪽', + chocolite_direction_dual: '양쪽(오른쪽,왼쪽)', + + chocolite_color_off: '끄기', + chocolite_color_blue: '파란색', + chocolite_color_red: '빨간색', + chocolite_color_green: '초록색', + chocolite_color_yellow: '노랑색', + chocolite_color_pink: '분홍색', + chocolite_color_bluegreen: '청록색', + chocolite_color_white: '흰색', + + chocolite_sound_car: '자동차', + chocolite_sound_robot: '로봇', + chocolite_sound_dog: '강아지', + chocolite_sound_cat: '고양이', + chocolite_sound_chicken: '닭', + chocolite_sound_tiger: '호랑이', + chocolite_sound_lion: '사자', + chocolite_sound_fart: '방귀소리', + chocolite_sound_helicopter: '헬리콥터', + chocolite_sound_train: '기차', + chocolite_sound_frog: '개구리', + chocolite_sound_jjajan: '짜잔(효과음)', + chocolite_sound_sheep: '양', + chocolite_sound_elephant: '코끼리', + chocolite_sound_camel: '낙타', + chocolite_sound_dolphin: '고래', + chocolite_sound_ttiyong: '띠용(효과음)', + chocolite_sound_hello_parrot: '헬로(앵무새)', + chocolite_sound_hello_manga: '헬로(만화)', + chocolite_sound_hello_man: '헬로(남자)', + chocolite_sound_ppong: '뽕(효과음)', + chocolite_sound_buzzer: '부저(효과음)', + chocolite_sound_ttalilalan: '따라리라란~(효과음)', + chocolite_sound_ttattattatta: '따따따따~(효과음)', + chocolite_sound_laughter: '웃음소리', + chocolite_sound_magic: '마술(효과음)', + chocolite_sound_woodpecker: '딱따구리', + chocolite_sound_bird: '새', + chocolite_sound_burp: '트림', + chocolite_sound_hiccup: '딸꾹질', + chocolite_sound_doridori: '도리도리', + chocolite_sound_firetruck: '소방차', + chocolite_sound_police_car: '경찰차', + chocolite_sound_applause: '박수환호', + chocolite_sound_kiss: '뽀뽀', + chocolite_sound_missile: '미사일', + chocolite_sound_angry_duck: '화난오리', + chocolite_sound_fly: '파리', + chocolite_sound_ufo: 'UFO', + chocolite_sound_fanfare: '팡파레', + chocolite_sound_sigh: '한숨소리', + chocolite_sound_alright: '올라잇~', + chocolite_sound_genius: '지니어스~', + chocolite_sound_no: '노우~', + chocolite_sound_wow: '오우~', + chocolite_sound_yahoo: '야호~', + + chocolite_sound_low_do: '낮은 도', + chocolite_sound_low_dosharp: '낮은 도#', + chocolite_sound_low_re: '낮은 레', + chocolite_sound_low_resharp: '낮은 레#', + chocolite_sound_low_mi: '낮은 미', + chocolite_sound_low_fa: '낮은 파', + chocolite_sound_low_fasharp: '낮은 파#', + chocolite_sound_low_sol: '낮은 솔', + chocolite_sound_low_solsharp: '낮은 솔#', + chocolite_sound_low_ra: '낮은 라', + chocolite_sound_low_rasharp: '낮은 라#', + chocolite_sound_low_si: '낮은 시', + chocolite_sound_do: '도', + chocolite_sound_dosharp: '도#', + chocolite_sound_re: '레', + chocolite_sound_resharp: '레#', + chocolite_sound_mi: '미', + chocolite_sound_fa: '파', + chocolite_sound_fasharp: '파#', + chocolite_sound_sol: '솔', + chocolite_sound_solsharp: '솔#', + chocolite_sound_ra: '라', + chocolite_sound_rasharp: '라#', + chocolite_sound_si: '시', + chocolite_sound_high_do: '높은 도', + chocolite_sound_high_dosharp: '높은 도#', + chocolite_sound_high_re: '높은 레', + chocolite_sound_high_resharp: '높은 레#', + chocolite_sound_high_mi: '높은 미', + chocolite_sound_high_fa: '높은 파', + chocolite_sound_high_fasharp: '높은 파#', + chocolite_sound_high_sol: '높은 솔', + chocolite_sound_high_solsharp: '높은 솔#', + chocolite_sound_high_ra: '높은 라', + chocolite_sound_high_rasharp: '높은 라#', + chocolite_sound_high_si: '높은 시', + }, + }, + en: { + template: { + chocolite_move_forward: 'move forward %1 %2 block %3', + chocolite_move_backward: 'move backward %1 %2 block %3', + chocolite_turn_left: '%1 %2 to the left %3', + chocolite_turn_right: '%1 %2 to the right %3', + chocolite_move_right_left: 'move right %1 left %2 %3 %4', + chocolite_onoff_led_rear: 'Rear LED %1 %2', + chocolite_set_led_color: '%1 LED %2 %3', + chocolite_play_sound: 'play %1 %2', + chocolite_is_front_sensor: 'front sensor', + chocolite_is_bottom_sensor: 'bottom sensor', + chocolite_is_light_sensor: 'light sensor', + chocolite_get_front_sensor: 'front sensor', + chocolite_get_bottom_sensor: 'bottom sensor', + chocolite_get_light_sensor: 'light sensor', + }, + Blocks: { + chocolite_move_step: 'step', + chocolite_move_cm: 'cm', + chocolite_trun_drgree: 'degree', + chocolite_trun_round: 'turns', + chocolite_toggle_on: 'on', + chocolite_toggle_off: 'off', + chocolite_direction_right: 'right', + chocolite_direction_left: 'left', + chocolite_direction_dual: 'all(right,left)', + + chocolite_color_off: 'off', + chocolite_color_blue: 'blue', + chocolite_color_red: 'red', + chocolite_color_green: 'green', + chocolite_color_yellow: 'yellow', + chocolite_color_pink: 'pink', + chocolite_color_bluegreen: 'bluegreen', + chocolite_color_white: 'white', + + chocolite_sound_car: 'car', + chocolite_sound_robot: 'robot', + chocolite_sound_dog: 'dog', + chocolite_sound_cat: 'cat', + chocolite_sound_chicken: 'chicken', + chocolite_sound_tiger: 'tiger', + chocolite_sound_lion: 'lion', + chocolite_sound_fart: 'fart', + chocolite_sound_helicopter: 'helicopter', + chocolite_sound_train: 'train', + chocolite_sound_frog: 'frog', + chocolite_sound_jjajan: 'jjajan(effect)', + chocolite_sound_sheep: 'sheep', + chocolite_sound_elephant: 'elephant', + chocolite_sound_camel: 'camel', + chocolite_sound_dolphin: 'dolphin', + chocolite_sound_ttiyong: 'ttiyong(effect)', + chocolite_sound_hello_parrot: 'hello(parrot)', + chocolite_sound_hello_manga: 'hello(manga)', + chocolite_sound_hello_man: 'hello(man)', + chocolite_sound_ppong: 'ppong(effect)', + chocolite_sound_buzzer: 'buzzer(effect)', + chocolite_sound_ttalilalan: 'ttalilalan(effect)', + chocolite_sound_ttattattatta: 'ttattattatta(effect)', + chocolite_sound_laughter: 'laughter', + chocolite_sound_magic: 'magic(effect)', + chocolite_sound_woodpecker: 'woodpecker', + chocolite_sound_bird: 'bird', + chocolite_sound_burp: 'burp', + chocolite_sound_hiccup: 'hiccup', + chocolite_sound_doridori: 'doridori', + chocolite_sound_firetruck: 'fire truck', + chocolite_sound_police_car: 'police car', + chocolite_sound_applause: 'applause', + chocolite_sound_kiss: 'kiss', + chocolite_sound_missile: 'missile', + chocolite_sound_angry_duck: 'angry duck', + chocolite_sound_fly: 'fly', + chocolite_sound_ufo: 'UFO', + chocolite_sound_fanfare: 'fanfare', + chocolite_sound_sigh: 'sigh', + chocolite_sound_alright: 'alright', + chocolite_sound_genius: 'genius', + chocolite_sound_no: 'no', + chocolite_sound_wow: 'wow', + chocolite_sound_yahoo: 'yahoo', + + chocolite_sound_low_do: 'low do', + chocolite_sound_low_dosharp: 'low do#', + chocolite_sound_low_re: 'low re', + chocolite_sound_low_resharp: 'low re#', + chocolite_sound_low_mi: 'low mi', + chocolite_sound_low_fa: 'low fa', + chocolite_sound_low_fasharp: 'low fa#', + chocolite_sound_low_sol: 'low sol', + chocolite_sound_low_solsharp: 'low sol#', + chocolite_sound_low_ra: 'low ra', + chocolite_sound_low_rasharp: 'low ra#', + chocolite_sound_low_si: 'low si', + chocolite_sound_do: 'do', + chocolite_sound_dosharp: 'do#', + chocolite_sound_re: 're', + chocolite_sound_resharp: 're#', + chocolite_sound_mi: 'mi', + chocolite_sound_fa: 'fa', + chocolite_sound_fasharp: 'fa#', + chocolite_sound_sol: 'sol', + chocolite_sound_solsharp: 'sol#', + chocolite_sound_ra: 'ra', + chocolite_sound_rasharp: 'ra#', + chocolite_sound_si: 'si', + chocolite_sound_high_do: 'high do', + chocolite_sound_high_dosharp: 'high do#', + chocolite_sound_high_re: 'high re', + chocolite_sound_high_resharp: 'high re#', + chocolite_sound_high_mi: 'high mi', + chocolite_sound_high_fa: 'high fa', + chocolite_sound_high_fasharp: 'high fa#', + chocolite_sound_high_sol: 'high sol', + chocolite_sound_high_solsharp: 'high sol#', + chocolite_sound_high_ra: 'high ra', + chocolite_sound_high_rasharp: 'high ra#', + chocolite_sound_high_si: 'high si', + }, + }, + }; + } + + getBlocks() { + return { + chocolite_move_forward: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_move_step, 'step'], + [Lang.Blocks.chocolite_move_cm, 'cm'], + ], + value: 'step', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, 'step', null], + type: 'chocolite_move_forward', + }, + paramsKeyMap: { + MOVE_CNT: 0, + MOVE_UNIT: 1, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const moveCnt = script.getValue('MOVE_CNT'); + const moveUnit = script.getValue('MOVE_UNIT'); + if (moveCnt === 0) { + return script.callReturn(); + } + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'move_forward', + data: { + param1: moveCnt, + param2: moveUnit, + }, + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_move_backward: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_move_step, 'step'], + [Lang.Blocks.chocolite_move_cm, 'cm'], + ], + value: 'step', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, 'step', null], + type: 'chocolite_move_backward', + }, + paramsKeyMap: { + MOVE_CNT: 0, + MOVE_UNIT: 1, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const moveCnt = script.getValue('MOVE_CNT'); + const moveUnit = script.getValue('MOVE_UNIT'); + if (moveCnt === 0) { + return script.callReturn(); + } + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'move_backward', + data: { + param1: moveCnt, + param2: moveUnit, + }, + }; + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_turn_left: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_trun_drgree, 'degree'], + [Lang.Blocks.chocolite_trun_round, 'turns'], + ], + value: 'degree', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [90, 'degree', null], + type: 'chocolite_turn_left', + }, + paramsKeyMap: { + TURN_CNT: 0, + TURN_UNIT: 1, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let turnCnt = script.getValue('TURN_CNT'); + const turnUnit = script.getValue('TURN_UNIT'); + if (turnCnt < 0) { + turnCnt = 0; + } + if (turnCnt === 0) { + return script.callReturn(); + } + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'turn_left', + data: { + param1: turnCnt, + param2: turnUnit, + }, + }; + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_turn_right: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_trun_drgree, 'degree'], + [Lang.Blocks.chocolite_trun_round, 'turns'], + ], + value: 'degree', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [90, 'degree', null], + type: 'chocolite_turn_right', + }, + paramsKeyMap: { + TURN_CNT: 0, + TURN_UNIT: 1, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let turnCnt = script.getValue('TURN_CNT'); + const turnUnit = script.getValue('TURN_UNIT'); + if (turnCnt < 0) { + turnCnt = 0; + } + if (turnCnt === 0) { + return script.callReturn(); + } + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'turn_right', + data: { + param1: turnCnt, + param2: turnUnit, + }, + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_move_right_left: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_move_step, 'step'], + [Lang.Blocks.chocolite_move_cm, 'cm'], + ], + value: 'step', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, 1, 'step', null], + type: 'chocolite_move_right_left', + }, + paramsKeyMap: { + MOVE_RIGHT_CNT: 0, + MOVE_LEFT_CNT: 1, + MOVE_UNIT: 2, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const moveRightCnt = script.getValue('MOVE_RIGHT_CNT'); + const moveLeftCnt = script.getValue('MOVE_LEFT_CNT'); + const moveUnit = script.getValue('MOVE_UNIT'); + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'move_right_left', + data: { + param1: moveRightCnt, + param2: moveLeftCnt, + param3: moveUnit, + }, + time: Date.now(), + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_onoff_led_rear: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_toggle_on, 'On'], + [Lang.Blocks.chocolite_toggle_off, 'Off'], + ], + value: 'On', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['On', null], + type: 'chocolite_onoff_led_rear', + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const ledOnoff = script.getValue('VALUE'); + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'onoff_led_rear', + data: { + param1: ledOnoff, + }, + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_set_led_color: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_direction_right, 'right'], + [Lang.Blocks.chocolite_direction_left, 'left'], + [Lang.Blocks.chocolite_direction_dual, 'dual'], + ], + value: 'right', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_color_off, 0], + [Lang.Blocks.chocolite_color_blue, 1], + [Lang.Blocks.chocolite_color_red, 2], + [Lang.Blocks.chocolite_color_green, 3], + [Lang.Blocks.chocolite_color_yellow, 4], + [Lang.Blocks.chocolite_color_pink, 5], + [Lang.Blocks.chocolite_color_bluegreen, 6], + [Lang.Blocks.chocolite_color_white, 7], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['right', 1, null], + type: 'chocolite_set_led_color', + }, + paramsKeyMap: { + DIRECTION: 0, + COLOR: 1, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const ledDir = script.getValue('DIRECTION'); + const ledColor = script.getValue('COLOR'); + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'set_led_color', + data: { + param1: ledDir, + param2: ledColor, + }, + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_play_sound: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.chocolite_sound_car, 1], + [Lang.Blocks.chocolite_sound_robot, 2], + [Lang.Blocks.chocolite_sound_dog, 3], + [Lang.Blocks.chocolite_sound_cat, 4], + [Lang.Blocks.chocolite_sound_chicken, 5], + [Lang.Blocks.chocolite_sound_tiger, 6], + [Lang.Blocks.chocolite_sound_lion, 7], + [Lang.Blocks.chocolite_sound_fart, 8], + [Lang.Blocks.chocolite_sound_helicopter, 9], + [Lang.Blocks.chocolite_sound_train, 10], + [Lang.Blocks.chocolite_sound_frog, 11], + [Lang.Blocks.chocolite_sound_jjajan, 12], + [Lang.Blocks.chocolite_sound_sheep, 13], + [Lang.Blocks.chocolite_sound_elephant, 14], + [Lang.Blocks.chocolite_sound_camel, 15], + [Lang.Blocks.chocolite_sound_dolphin, 16], + [Lang.Blocks.chocolite_sound_ttiyong, 17], + [Lang.Blocks.chocolite_sound_hello_parrot, 18], + [Lang.Blocks.chocolite_sound_hello_manga, 19], + [Lang.Blocks.chocolite_sound_hello_man, 20], + [Lang.Blocks.chocolite_sound_ppong, 21], + [Lang.Blocks.chocolite_sound_buzzer, 22], + [Lang.Blocks.chocolite_sound_ttalilalan, 23], + [Lang.Blocks.chocolite_sound_ttattattatta, 24], + [Lang.Blocks.chocolite_sound_laughter, 25], + [Lang.Blocks.chocolite_sound_magic, 26], + [Lang.Blocks.chocolite_sound_woodpecker, 27], + [Lang.Blocks.chocolite_sound_bird, 28], + [Lang.Blocks.chocolite_sound_burp, 29], + [Lang.Blocks.chocolite_sound_hiccup, 30], + [Lang.Blocks.chocolite_sound_doridori, 31], + [Lang.Blocks.chocolite_sound_firetruck, 32], + [Lang.Blocks.chocolite_sound_police_car, 33], + [Lang.Blocks.chocolite_sound_applause, 34], + [Lang.Blocks.chocolite_sound_kiss, 35], + [Lang.Blocks.chocolite_sound_missile, 36], + [Lang.Blocks.chocolite_sound_angry_duck, 37], + [Lang.Blocks.chocolite_sound_fly, 38], + [Lang.Blocks.chocolite_sound_ufo, 39], + [Lang.Blocks.chocolite_sound_fanfare, 40], + [Lang.Blocks.chocolite_sound_sigh, 41], + [Lang.Blocks.chocolite_sound_alright, 42], + [Lang.Blocks.chocolite_sound_genius, 43], + [Lang.Blocks.chocolite_sound_no, 44], + [Lang.Blocks.chocolite_sound_wow, 45], + [Lang.Blocks.chocolite_sound_yahoo, 46], + + [Lang.Blocks.chocolite_sound_low_do, 47], + [Lang.Blocks.chocolite_sound_low_dosharp, 48], + [Lang.Blocks.chocolite_sound_low_re, 49], + [Lang.Blocks.chocolite_sound_low_resharp, 50], + [Lang.Blocks.chocolite_sound_low_mi, 51], + [Lang.Blocks.chocolite_sound_low_fa, 52], + [Lang.Blocks.chocolite_sound_low_fasharp, 53], + [Lang.Blocks.chocolite_sound_low_sol, 54], + [Lang.Blocks.chocolite_sound_low_solsharp, 55], + [Lang.Blocks.chocolite_sound_low_ra, 56], + [Lang.Blocks.chocolite_sound_low_rasharp, 57], + [Lang.Blocks.chocolite_sound_low_si, 58], + [Lang.Blocks.chocolite_sound_do, 59], + [Lang.Blocks.chocolite_sound_dosharp, 60], + [Lang.Blocks.chocolite_sound_re, 61], + [Lang.Blocks.chocolite_sound_resharp, 62], + [Lang.Blocks.chocolite_sound_mi, 63], + [Lang.Blocks.chocolite_sound_fa, 64], + [Lang.Blocks.chocolite_sound_fasharp, 65], + [Lang.Blocks.chocolite_sound_sol, 66], + [Lang.Blocks.chocolite_sound_solsharp, 67], + [Lang.Blocks.chocolite_sound_ra, 68], + [Lang.Blocks.chocolite_sound_rasharp, 69], + [Lang.Blocks.chocolite_sound_si, 70], + [Lang.Blocks.chocolite_sound_high_do, 71], + [Lang.Blocks.chocolite_sound_high_dosharp, 72], + [Lang.Blocks.chocolite_sound_high_re, 73], + [Lang.Blocks.chocolite_sound_high_resharp, 74], + [Lang.Blocks.chocolite_sound_high_mi, 75], + [Lang.Blocks.chocolite_sound_high_fa, 76], + [Lang.Blocks.chocolite_sound_high_fasharp, 77], + [Lang.Blocks.chocolite_sound_high_sol, 78], + [Lang.Blocks.chocolite_sound_high_solsharp, 79], + [Lang.Blocks.chocolite_sound_high_ra, 80], + [Lang.Blocks.chocolite_sound_high_rasharp, 81], + [Lang.Blocks.chocolite_sound_high_si, 82], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'chocolite_play_sound', + }, + paramsKeyMap: { + SOUND: 0, + }, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + const sound = script.getValue('SOUND'); + + if (!script.is_started) { + script.is_started = true; + const msg = { + type: 'play_sound', + data: { + param1: sound, + }, + }; + + const sendData = this.makeData(msg); + script.isDone = false; + this.sendBuffers.push({ + sendData, + cb: () => { + script.isDone = true; + }, + }); + return script; + } + + if (script.isDone) { + delete script.is_started; + delete script.isDone; + return script.callReturn(); + } + return script; + }, + }, + chocolite_is_front_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_is_front_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = false; + if (this.sensorData) { + retVal = this.sensorData.is_front_sensor; + } + return retVal; + }, + }, + chocolite_is_bottom_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_is_bottom_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = false; + if (this.sensorData) { + retVal = this.sensorData.is_bottom_sensor; + } + return retVal; + }, + }, + chocolite_is_light_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_is_light_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = false; + if (this.sensorData) { + retVal = this.sensorData.is_light_sensor; + } + return retVal; + }, + }, + + chocolite_get_front_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_get_front_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = 0; + if (this.sensorData) { + retVal = this.sensorData.front_sensor; + } + return retVal; + }, + }, + chocolite_get_bottom_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_get_bottom_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = 0; + if (this.sensorData) { + retVal = this.sensorData.bottom_sensor; + } + return retVal; + }, + }, + chocolite_get_light_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Text', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'chocolite_get_light_sensor', + }, + paramsKeyMap: {}, + class: 'chocolite_command', + isNotFor: ['ChocoLite'], + func: (sprite, script) => { + let retVal = 0; + if (this.sensorData) { + retVal = this.sensorData.light_sensor; + } + return retVal; + }, + }, + }; + } + + /*************************************************************************************** + * 프로토롤 제어 함수 + ***************************************************************************************/ + sequenceNo() { + if (this.cmdSeq > 254) { + this.cmdSeq = 0; + } else { + this.cmdSeq++; + } + return this.cmdSeq; + } + + calMoveVal(args) { + let retval = 0; + if (args.param2 === 'cm') { + retval = parseInt(args.param1 * 10, 10); + if (args.param1 > 0 && retval === 0) { + retval = 1; + } + } else { + retval = args.param1 * 10; + } + retval = parseInt(retval, 10); + if (retval < 0) { + retval = 0; + } + if (retval > 990) { + retval = 990; + } + return retval; + } + + calTurnVal(args) { + let retval = 0; + if (args.param2 === 'degree') { + retval = parseInt((args.param1 * 10) / 90, 10); + if (args.param1 > 0 && retval === 0) { + retval = 1; + } + } else { + retval = args.param1 * 10 * 4; + } + retval = parseInt(retval, 10); + if (retval < 0) { + retval = 0; + } + if (retval > 990) { + retval = 990; + } + return retval; + } + + calLedCol(args) { + let rightLed = 0; + let leftLed = 0; + + if (args.param1 === 'right') { + rightLed = args.param2; + } else if (args.param1 === 'left') { + leftLed = args.param2; + } else if (args.param1 === 'dual') { + rightLed = args.param2; + leftLed = args.param2; + } + + return { + rightLed, + leftLed, + }; + } + + /*************************************************************************************** + * Protocol 데이터 생성 + ***************************************************************************************/ + makeData(msg) { + const seqNo = this.sequenceNo(); + let data = null; + let crc = 0; + let encodedCmd = []; + + const type = msg.type; + let args = {}; + if (msg.data) { + args = msg.data; + } + + switch (type) { + case 'ping': + data = Buffer.from([0x03, seqNo]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'ping2': + data = Buffer.from([0x13, seqNo]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'ping3': + data = Buffer.from([0x14, seqNo]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'ping2_end': + data = Buffer.from([0x17, seqNo]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'ready': + data = Buffer.from([0x04, seqNo]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'move_forward': + if (args.param2 === 'cm') { + data = Buffer.from([0x19, seqNo, 0, 0, 0, 0]); + } else { + data = Buffer.from([0x05, seqNo, 0, 0, 0, 0]); + } + data.writeUInt32LE(this.calMoveVal(args), 2); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'move_backward': + if (args.param2 === 'cm') { + data = Buffer.from([0x1a, seqNo, 0, 0, 0, 0]); + } else { + data = Buffer.from([0x06, seqNo, 0, 0, 0, 0]); + } + data.writeUInt32LE(this.calMoveVal(args), 2); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'turn_left': + data = Buffer.from([0x07, seqNo, 0, 0, 0, 0]); + data.writeUInt32LE(this.calTurnVal(args), 2); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'turn_right': + data = Buffer.from([0x08, seqNo, 0, 0, 0, 0]); + data.writeUInt32LE(this.calTurnVal(args), 2); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + + case 'move_right_left': { + if (args.param3 === 'cm') { + data = Buffer.from([0x1b, seqNo, 0, 0, 0, 0, 0, 0, 0, 0]); + } else { + data = Buffer.from([0x0d, seqNo, 0, 0, 0, 0, 0, 0, 0, 0]); + } + const args1 = { + param1: args.param1, + param2: args.param3, + }; + const args2 = { + param1: args.param2, + param2: args.param3, + }; + data.writeUInt32LE(this.calMoveVal(args1), 2); + data.writeUInt32LE(this.calMoveVal(args2), 6); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + } + + case 'onoff_led_rear': { + const rearLed = args.param1 === 'On' ? 1 : 0; + this.ledStatus[2] = rearLed; + data = Buffer.from([ + 0x0b, + seqNo, + this.ledStatus[0], + this.ledStatus[1], + this.ledStatus[2], + ]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + } + + case 'set_led_color': { + const { rightLed, leftLed } = this.calLedCol(args); + if (args.param1 === 'right') { + this.ledStatus[0] = rightLed; + } else if (args.param1 === 'left') { + this.ledStatus[1] = leftLed; + } else if (args.param1 === 'dual') { + this.ledStatus[0] = rightLed; + this.ledStatus[1] = leftLed; + } + data = Buffer.from([ + 0x0b, + seqNo, + this.ledStatus[0], + this.ledStatus[1], + this.ledStatus[2], + ]); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + } + + case 'play_sound': + data = Buffer.from([0x0f, seqNo, 0, 0, 0, 0]); + data.writeUInt32LE(args.param1, 2); + crc = this.calCrc16(data); + encodedCmd = this.escapeEncode( + Buffer.concat([data, Buffer.from([crc & 0xff, (crc >> 8) & 0xff])]) + ); + break; + } + + const cmdData = Buffer.from([0x7c, ...encodedCmd, 0x7e]); + //console.log(cmdData); + return cmdData; + } + + /*************************************************************************************** + * 데이터 encoding + ***************************************************************************************/ + escapeEncode(data) { + const buffer = Buffer.alloc(data.length * 2); + let idx = 0; + for (const d of data) { + if (d === 0x7c) { + buffer[idx] = 0x7d; + buffer[idx + 1] = 0x5c; + idx += 2; + } else if (d === 0x7d) { + buffer[idx] = 0x7d; + buffer[idx + 1] = 0x5d; + idx += 2; + } else if (d === 0x7e) { + buffer[idx] = 0x7d; + buffer[idx + 1] = 0x5e; + idx += 2; + } else { + buffer[idx] = d; + idx++; + } + } + return buffer.slice(0, idx); + } + + /*************************************************************************************** + * 데이터 decoding + ***************************************************************************************/ + escapeEecode(data) { + const buffer = Buffer.alloc(data.length); + let idx = 0; + let i = 0; + while (i < data.length) { + if (data[i] === 0x7d) { + buffer[idx++] = data[i + 1] ^ 0x20; + i += 2; + } else { + buffer[idx++] = data[i++]; + } + } + return buffer.slice(0, idx); + } + + /*************************************************************************************** + * CRC 생성 + ***************************************************************************************/ + calCrc16(data) { + let res = 0x0ffff; + + for (const b of data) { + res = ((res >> 8) & 0x0ff) ^ this.crctab16[(res ^ b) & 0xff]; + } + + return ~res & 0x0ffff; + } + + /*************************************************************************************** + * 로그 출력 + ***************************************************************************************/ + // #region Functions for log + + log(message, data = undefined) { + // 로그를 출력하지 않으려면 아래 주석을 활성화 할 것 + let strInfo = ''; + switch (typeof data) { + case 'object': + { + strInfo = ` - [ ${this.convertByteArrayToHexString(data)} ]`; + console.log(`${message} - ${typeof data}${strInfo}`); + } + break; + default: + { + console.log(message); + } + break; + } + } + + // 바이트 배열을 16진수 문자열로 변경 + convertByteArrayToHexString(data) { + let strHexArray = ''; + let strHex; + + if (typeof data === 'object' && data.length > 1) { + for (let i = 0; i < data.length; i++) { + strHex = data[i].toString(16).toUpperCase(); + strHexArray += ' '; + if (strHex.length === 1) { + strHexArray += '0'; + } + strHexArray += strHex; + } + strHexArray = strHexArray.substr(1, strHexArray.length - 1); + } else { + strHexArray = data.toString(); + } + + return strHexArray; + } + })(); +})(); + +module.exports = Entry.ChocoLite; diff --git a/src/playground/blocks/hardwareLite/block_microbit2_lite.js b/src/playground/blocks/hardwareLite/block_microbit2_lite.js index a74f28e860..4b21098631 100644 --- a/src/playground/blocks/hardwareLite/block_microbit2_lite.js +++ b/src/playground/blocks/hardwareLite/block_microbit2_lite.js @@ -4,12 +4,12 @@ const _throttle = require('lodash/throttle'); const EVENT_INTERVAL = 150; -(function () { +(function() { Entry.Microbit2lite = new (class Microbit2Lite { constructor() { this.commandStatus = {}; this.btnEventIntervalId = -1; - this.retryLimitCnt = 5; + this.retryLimitCnt = 4; this.portData = { baudRate: 115200, dataBits: 8, @@ -292,7 +292,7 @@ const EVENT_INTERVAL = 150; async initialHandshake() { const defaultCMD = `${this.functionKeys.LOCALDATA}`; - const response = await Entry.hwLite.sendAsync(defaultCMD); + const response = await Entry.hwLite.sendAsyncWithThrottle(defaultCMD); if (response && response.indexOf('localdata') > -1) { const version = response.split(';')[1]; if (!version) { @@ -306,14 +306,19 @@ const EVENT_INTERVAL = 150; if (this.version === '2') { Entry.addEventListener('run', this.handleBtnEventInterval.bind(this)); - Entry.addEventListener('beforeStop', () => { clearInterval(this.btnEventIntervalId) }); + Entry.addEventListener('beforeStop', () => { + clearInterval(this.btnEventIntervalId); + }); } return response; } handleBtnEventInterval() { - this.btnEventIntervalId = setInterval(this.listenBtnPressedEvent.bind(this), this.duration); + this.btnEventIntervalId = setInterval( + this.listenBtnPressedEvent.bind(this), + this.duration + ); } async listenBtnPressedEvent() { @@ -372,9 +377,8 @@ const EVENT_INTERVAL = 150; return; } const result = await Entry.hwLite.sendAsyncWithThrottle(command); - - if (!result || - this.getCommandType(command) !== this.getCommandType(result) || + if ( + (!result || this.getCommandType(command) !== this.getCommandType(result)) && // INFO : localdata 명령어는 우선순위가 낮으므로 반복하지 않음 command !== `${this.functionKeys.LOCALDATA};` ) { @@ -582,7 +586,8 @@ const EVENT_INTERVAL = 150; microbit2lite_get_btn: "선택한 버튼이 눌렸다면 '참'으로 판단합니다.", microbit2lite_get_logo: "로고를 터치했다면 '참'으로 판단합니다.", microbit2lite_get_gesture: "선택한 움직임이 감지되면 '참'으로 판단합니다.", - microbit2lite_get_acc: '선택한 버튼이 눌리면 아래에 연결된 블록들을 실행합니다.', + microbit2lite_get_acc: + '선택한 버튼이 눌리면 아래에 연결된 블록들을 실행합니다.', microbit2lite_btn_event: '%1 %2 버튼을 눌렀을 때', microbit2lite_get_direction: '나침반 방향 값입니다. (0~360) ', microbit2lite_get_field_strength_axis: '선택한 축의 자기장 세기 값입니다.', @@ -793,7 +798,8 @@ const EVENT_INTERVAL = 150; microbit2lite_get_gesture: "When the selected movement is detected, it is judged as 'True'.", microbit2lite_get_acc: 'The acceleration value of the selected axis.', - microbit2lite_btn_event: 'When the selected button is pressed, the connected blocks below will run', + microbit2lite_btn_event: + 'When the selected button is pressed, the connected blocks below will run', microbit2lite_get_direction: 'The compass direction value. (0~360)', microbit2lite_get_field_strength_axis: 'The magnetic field strength value of the selected axis.', @@ -1012,7 +1018,7 @@ const EVENT_INTERVAL = 150; }; } - getBlocks = function () { + getBlocks = function() { return { microbit2lite_common_title: { skeleton: 'basic_text', @@ -1952,7 +1958,7 @@ const EVENT_INTERVAL = 150; }, ], def: { - type: 'microbit2lite_btn_event' + type: 'microbit2lite_btn_event', }, paramsKeyMap: { VALUE: 1, @@ -2362,7 +2368,7 @@ const EVENT_INTERVAL = 150; }, { type: 'Indicator', - img: 'block_icon/hardware_icon.svg', + img: 'block_icon/hardwarelite_icon.svg', size: 12, }, ], @@ -2412,7 +2418,7 @@ const EVENT_INTERVAL = 150; }, { type: 'Indicator', - img: 'block_icon/hardware_icon.svg', + img: 'block_icon/hardwarelite_icon.svg', size: 12, }, ], diff --git a/src/playground/blocks/hardwareLite/block_neo_lite.js b/src/playground/blocks/hardwareLite/block_neo_lite.js new file mode 100644 index 0000000000..9d3f733c4b --- /dev/null +++ b/src/playground/blocks/hardwareLite/block_neo_lite.js @@ -0,0 +1,6282 @@ +'use strict'; +(function() { + /* + 엔트리에 정의된 블럭 명령어 + 엔트리에서 받을 때는 BlockTypes 로 통신하고, + 하드웨어로 전송할 때는 Command 로 변환 후 Pdu 로 Wrapping 하여 전송한다. + */ + const NeoBlockType = { + // MOTOR 명령어 0x1X + MOTOR_MOVE: 0x11, + MOTOR_MOVE_BOTH: 0x12, + MOTOR_STOP: 0x13, + ROBOT_MOVE: 0x14, + ROBOT_STOP: 0x15, + // SERVO 명령어 0x2X + SERVO_RESET: 0x21, + SERVO_ANGLE: 0x22, + SERVO_ANGLE_WAIT: 0x23, + SERVO_ROTATE: 0x24, + SERVO_STOP: 0x25, + // LINE_TRACER 명령어 0x3X + LINE_TRACER_START: 0x31, + LINE_CROSS_MOVE: 0x32, + LINE_CROSS_TURN: 0x33, + LINE_CHANGE_START: 0x34, + LINE_CHANGE_TURN: 0x35, + // AUTO_DRIVING 명령어 0x4X + AUTO_DRIVING_START: 0x41, + AUTO_DRIVING_SENSOR_START: 0x42, + AUTO_DRIVING_STOP: 0x43, + AUTO_PARKING_START: 0x44, + AUTO_DETECT_WALL_START: 0x45, + AUTO_DETECT_WALL_TURN: 0x46, + // LED 명령어 0x5X + LED_ON: 0x51, + LED_BLINK: 0x52, + LED_OFF: 0x53, + COLOR_LED_ON: 0x54, + COLOR_LED_OFF: 0x55, + COLOR_LED_ON_SENSOR: 0x56, + // SET_OUTPUT 명령어 0x6X + SET_OUTPUT: 0x61, + // BUZZER 명령어 0x7X + BUZZER_START: 0x71, + BUZZER_WITH_SENSOR: 0x72, + BUZZER_STOP: 0x73, + // LCD 명령어 0x8X + LCD_IMAGE: 0x81, + LCD_TEXT: 0x82, + }; + + /* + PDU 정의 + */ + const HEADER = [0xaa, 0xaa, 0xcc]; + const IDX_LENGTH = 3; + const IDX_FRAME_CODE = 4; + const IDX_PDU_CODE = 5; + const IDX_ACK_NUM = 6; + + const FrameCode = { + BASIC: 0x01, + CONNECTION: 0x02, + }; + + const PduConnectionCode = { + PAIRING_START: 0x01, + PAIRING_INFO: 0x03, + PAIRING_REMOVE: 0x06, + NOTIFY_LIVE: 0x07, + }; + + const PduBasicCode = { + SENSOR_DATA: 0x01, + BASIC: 0x10, + EXTEND_1: 0x11, + }; + + const SensorKind = { + CONTROLLER: 0x00, + ANALOG: 0x01, + COLOR: 0x02, + DISTANCE: 0x03, + TEMPERATURE: 0x04, + GYRO: 0x05, + }; + + const PduCode = { + SENSOR_DATA: 0x01, + CONTROLLER_COMMAND: 0x02, + ACTION_COMMAND: 0x03, + BASIC: 0x10, + EXTEND_1: 0x11, + EXTEND_2: 0x12, + EXTEND_3: 0x13, + }; + + const ActorKind = { + CONTROLLER: 0x00, + LED: 0x80, + SERVO: 0x81, + COLOR_LED: 0x82, + LCD: 0x83, + }; + + const ControllerCommand = { + CONTROLLER_LED: 0x01, + BUZZER: 0x02, + MOTOR: 0x03, + MOTOR_BOTH: 0x04, + ROBOT: 0x05, + LINE_TRACER: 0x06, + AUTO_DRIVING: 0x07, + AUTO_PARKING: 0x08, + AUTO_DETECT_WALL: 0x09, + }; + + const ServoCommand = { + STOP: 0x01, + RESET: 0x02, + ANGLE: 0x03, + ANGLE_WAIT: 0x04, + ROTATE: 0x05, + }; + + const LedCommand = { + OFF: 0x00, + ON: 0x01, + }; + + const LcdCommand = { + IMAGE: 0x01, + TEXT: 0x02, + }; + + const UnitId = { + CONTROLLER: 0x00, + CONTROLLER_IN1: 0x01, + CONTROLLER_IN2: 0x02, + CONTROLLER_IN3: 0x03, + SENSOR_STICK: 0x10, + SENSOR_STICK_IN1: 0x11, + IOT: 0x80, + CONTROLLER_OUT1: 0x81, + CONTROLLER_OUT2: 0x82, + CONTROLLER_OUT12: 0x83, + CONTROLLER_OUT3: 0x84, + CONTROLLER_OUT13: 0x85, + CONTROLLER_OUT23: 0x86, + CONTROLLER_OUT123: 0x87, + CONTROLLER_OUT_ALL: 0x8f, + }; + + /* + 블럭 실행 단계 + execute: 최초 실행 + pending_response: 최초 실행의 response 대기중인 상태 + set_timeout: 블럭에서 duration 필드에 의거하여 타임아웃을 설정 + wait_timeout: timeout 대기중인 상태 + stop: 파라미터를 0으로 바꿔서 실행 + pending_stop: 파라미터를 0으로 바꾼 실행의 response 대기중인 상태 + end: 실행 종료 단계 + */ + const ExecPhase = { + EXECUTE: 'execute', + PENDING_RESPONSE: 'pending_response', + SET_TIMEOUT: 'set_timeout', + WAIT_TIMEOUT: 'wait_timeout', + STOP: 'stop', + PENDING_STOP: 'pending_stop', + END: 'end', + }; + + Entry.NeoLite = new (class NeoLite { + constructor() { + this.id = '5.8'; + this.name = 'NeoLite'; + this.url = 'http://neobot.co.kr/'; + this.imageName = 'neo_lite.png'; + this.portData = { + baudRate: 500000, + dataBits: 8, + parity: 'none', + stopBits: 1, + bufferSize: 512, + duration: 32, + constantServing: true, + }; + this.duration = 32; + + this.sensorValues = { + controllerBattery: 0, + irCode: 0, + in1Kind: 0, + in1Values: [0, 0, 0, 0], + in2Kind: 0, + in2Values: [0, 0, 0, 0], + in3Kind: 0, + in3Values: [0, 0, 0, 0], + sensorStickBattery: 0, + in4Kind: 0, + in4Values: [0, 0, 0, 0], + }; // 센서 데이터 + + this.blockMenuBlocks = [ + // motor & robot + 'neo_lite_motor_title', + 'neo_lite_motor_move', + 'neo_lite_motor_move_both', + 'neo_lite_robot_move', + 'neo_lite_motor_stop', + 'neo_lite_robot_stop', + // servo + 'neo_lite_servo_title', + 'neo_lite_servo_reset', + 'neo_lite_servo_angle', + 'neo_lite_servo_angle_var', + 'neo_lite_servo_angle_wait', + 'neo_lite_servo_rotate', + 'neo_lite_servo_stop', + // line tracer + 'neo_lite_line_tracer_title', + 'neo_lite_line_tracer_start', + 'neo_lite_line_cross_move', + 'neo_lite_line_cross_turn', + // auto driving + 'neo_lite_auto_driving_title', + 'neo_lite_auto_driving_start', + 'neo_lite_auto_driving_sensor_start', + 'neo_lite_auto_driving_stop', + // auto parking + 'neo_lite_auto_parking_title', + 'neo_lite_auto_parking_start', + /*// line change + 'neo_lite_line_change_title', + 'neo_lite_line_change_start', + 'neo_lite_line_change_turn', + // auto detect wall + 'neo_lite_auto_detect_wall_title', + 'neo_lite_auto_detect_wall_start', + 'neo_lite_auto_detect_wall_turn',*/ + // led + 'neo_lite_led_title', + 'neo_lite_led_on', + 'neo_lite_led_blink', + 'neo_lite_led_off', + // color led + 'neo_lite_color_led_title', + 'neo_lite_color_led_on', + 'neo_lite_color_led_off', + 'neo_lite_color_led_on_with_sensor', + // set output + 'neo_lite_set_output_title', + 'neo_lite_set_output', + // sensor + 'neo_lite_sensor_title', + 'neo_lite_sensor_in', + 'neo_lite_sensor_digital_in', + 'neo_lite_sensor_convert', + 'neo_lite_sensor_compare', + 'neo_lite_sensor_between', + 'neo_lite_sensor_color_compare', + 'neo_lite_sensor_button_pressed', + // lcd + 'neo_lite_lcd_title', + 'neo_lite_lcd_image', + 'neo_lite_lcd_text', + // buzzer + 'neo_lite_buzzer_title', + 'neo_lite_buzzer_start', + 'neo_lite_buzzer_with_sensor', + 'neo_lite_buzzer_stop', + ]; + + this.executeList = []; + this.pendingResponseList = {}; + + this.isDebug = false; + this.isDebugSensor = false; + this.isDebugPdu = false; + + this.seqBlockId = 0; + + this.setZero(); + } + + get monitorTemplate() { + return { + imgPath: 'hw/neo.png', + width: 700, + height: 700, + listPorts: { + IN11: { name: 'IN1 1', type: 'input', pos: { x: 0, y: 0 } }, + IN12: { name: 'IN1 2', type: 'input', pos: { x: 0, y: 0 } }, + IN13: { name: 'IN1 3', type: 'input', pos: { x: 0, y: 0 } }, + IN14: { name: 'IN1 4', type: 'input', pos: { x: 0, y: 0 } }, + IN21: { name: 'IN2 1', type: 'input', pos: { x: 0, y: 0 } }, + IN22: { name: 'IN2 2', type: 'input', pos: { x: 0, y: 0 } }, + IN23: { name: 'IN2 3', type: 'input', pos: { x: 0, y: 0 } }, + IN24: { name: 'IN2 4', type: 'input', pos: { x: 0, y: 0 } }, + IN31: { name: 'IN3 1', type: 'input', pos: { x: 0, y: 0 } }, + IN32: { name: 'IN3 2', type: 'input', pos: { x: 0, y: 0 } }, + IN33: { name: 'IN3 3', type: 'input', pos: { x: 0, y: 0 } }, + IN34: { name: 'IN3 4', type: 'input', pos: { x: 0, y: 0 } }, + IR: { name: 'IR', type: 'input', pos: { x: 0, y: 0 } }, + BAT: { name: 'BAT', type: 'input', pos: { x: 0, y: 0 } }, + }, + mode: 'both', + }; + } + + setZero() { + /*if (Entry.Lite) { + Entry.hwLite.update(); + }*/ + if (Entry.hwLite) { + const blockId = this.generateBlockId(); + const pdu = this.makePdu([FrameCode.BASIC, PduCode.CONTROLLER_COMMAND, blockId, 0x04]); + // Entry.hwLite.writer.write(Buffer.from(pdu)); + this.executeList = [ + { + blockId, + pdu, + }, + ]; + Entry.hwLite.update(); + } + } + + /* + 연결 후 초기에 송신할 데이터가 필요한 경우 사용합니다. + requestInitialData 를 사용한 경우 checkInitialData 가 필수입니다. + 이 두 함수가 정의되어있어야 로직이 동작합니다. 필요없으면 작성하지 않아도 됩니다. + */ + requestInitialData() { + this.logPdu('request initial data (request paring info to hw)'); + return this.makePdu(this.getPairingInfoCmd()); + } + + validateLocalData(pdu) { + return true; + } + + async initialHandshake() { + const initPdu = this.requestInitialData(); + this.executeList.push({ + blockId: 0, + pdu: initPdu, + }); + Entry.hwLite.update(); + return true; + } + + /** + * 하드웨어에서 온 데이터 처리 + * @param {ArrayBuffer} data + */ + handleLocalData(data) { + this.logPdu(`incoming pdu : ${this.byteArrayToHex(data)}`); + let validPdu = this.getValidPdu(data); + while (validPdu) { + this.onReceivePdu(validPdu); + if (!this.remainingPdu || this.remainingPdu.length <= 0) { + break; + } + validPdu = this.getValidPdu([]); + } + } + + /** + * remainingPdu 와 병합 처리하여 유효한 pdu 를 반환한다. + * 전체 길이가 짧을 경우 remainingPdu 에 저장 후 다음에 오는 패킷과 병합하여 처리함. + * 전체 길이가 Pdu Length 보다 길 경우 유효한 부분까지만 잘라 쓰고 + * 나머지는 remainingPdu 에 저장 후 다음에 오는 패킷과 병합하여 처리함. + * @param pdu + * @return {null|Array} validPdu + */ + getValidPdu(pdu) { + const mergedPdu = []; + if (this.remainingPdu) { + mergedPdu.push(...this.remainingPdu); + this.remainingPdu = null; + } + mergedPdu.push(...pdu); + this.logPdu(`merged pdu : ${this.byteArrayToHex(mergedPdu)}`); + if (mergedPdu.length < 4) { + this.remainingPdu = [...mergedPdu]; + this.logPdu(`too short header : ${this.byteArrayToHex(mergedPdu)}`); + return null; + } + + // 헤더 불일치는 버림 + if (!this.checkHeader(mergedPdu)) { + this.logPdu(`incorrect header : ${this.byteArrayToHex(mergedPdu)}`); + return null; + } + + // 유효 데이터 길이는 data length + header length (3) + length byte (1) + checksum byte (1) + const validDataLength = mergedPdu[IDX_LENGTH] + HEADER.length + 1 + 1; + /* + 전체 길이가 유효 데이터 길이보다 작을 경우 + 아직 도착하지 않은 부분이 있으므로 병합을 위해 remainingPdu 에 저장 + */ + if (mergedPdu.length < validDataLength) { + this.logPdu(`too short pdu : ${this.byteArrayToHex(mergedPdu)}`); + this.remainingPdu = [...mergedPdu]; + this.logPdu(`remaining pdu : ${this.byteArrayToHex(this.remainingPdu)}`); + return null; + } + + /* + 전체 길이가 유효 데이터 길이보다 클 경우 + 유효한 부분만 잘라내고 나머지는 remainingPdu 에 저장 + */ + if (mergedPdu.length > validDataLength) { + this.logPdu(`too long pdu : ${this.byteArrayToHex(mergedPdu)}`); + this.remainingPdu = mergedPdu.slice(validDataLength, mergedPdu.length); + this.logPdu(`remaining pdu : ${this.byteArrayToHex(this.remainingPdu)}`); + } + + const validPdu = mergedPdu.slice(0, validDataLength); + //this.logPdu(`valid pdu : ${this.byteArrayToHex(validPdu)}`); + + /* + 유효 Pdu 의 checksum 확인 + */ + const dataLength = validPdu[IDX_LENGTH]; + let checkSum = 0; + for (let i = 0; i < dataLength; i++) { + checkSum += validPdu[i + 4]; + } + checkSum = checkSum & 255; + const pduCheckSum = validPdu[HEADER.length + 1 + dataLength]; + if (pduCheckSum !== checkSum) { + this.logPdu(`checksum error : ${pduCheckSum} ${checkSum}`); + return null; + } + + if (validPdu[IDX_FRAME_CODE] === 0xfe) { + this.logPdu('error data arrived!!'); + } + + return validPdu; + } + + /** + * 유효한 pdu 수신 처리함. + * 센서 데이터 수신, Action Command 의 Response 만 처리함. + * 나머지는 NEO Platform 전용이므로 무시함. + * @param pdu + */ + onReceivePdu(pdu) { + if (pdu[IDX_FRAME_CODE] === FrameCode.BASIC) { + if (pdu[IDX_PDU_CODE] === PduBasicCode.SENSOR_DATA) { + // this.logD(this.byteArrayToHex(pdu)); + this.parseSensorPdu(pdu); + return; + } + + this.logD(this.byteArrayToHex(pdu)); + + const responseData = this.parseResponsePdu(pdu); + + if (responseData && responseData.blockId) { + if (this.pendingResponseList[responseData.blockId]) { + if (responseData.result === 0x02) { + this.pendingResponseList[responseData.blockId] = 'pending'; + } + if (responseData.result === 0x01) { + // this.pendingResponseList[responseData.blockId] = 'completed'; + delete this.pendingResponseList[responseData.blockId]; + } + } + } + } + } + + parseSensorPdu(pdu) { + let body = pdu.slice(IDX_PDU_CODE + 1, pdu.length - 1); + this.logSensor(`sensor pdu : ${this.byteArrayToHex(body)}`); + while (body && body.length > 0) { + const sensorDataKind = body[0]; + const unitId = body[1]; + const valueLength = body[2]; + const value = body.slice(3, 3 + valueLength); + const buffer = Buffer.from(value); + if (sensorDataKind === SensorKind.CONTROLLER) { + if (unitId === UnitId.CONTROLLER) { + this.sensorValues.irCode = buffer.readInt16LE(2); + this.sensorValues.controllerBattery = buffer.readInt16LE(4); + } + } + if (sensorDataKind === SensorKind.ANALOG) { + const analogValue = buffer.readInt16LE(0); + if (unitId === UnitId.CONTROLLER_IN1) { + this.sensorValues.in1Values = [analogValue, 0, 0, 0]; + } else if (unitId === UnitId.CONTROLLER_IN2) { + this.sensorValues.in2Values = [analogValue, 0, 0, 0]; + } else if (unitId === UnitId.CONTROLLER_IN3) { + this.sensorValues.in3Values = [analogValue, 0, 0, 0]; + } + } else if (sensorDataKind === SensorKind.COLOR) { + const value1 = buffer.readInt16LE(0); + const value2 = buffer.readInt16LE(2); + const value3 = buffer.readInt16LE(4); + const value4 = buffer.readInt16LE(6); + if (unitId === UnitId.CONTROLLER_IN1) { + this.sensorValues.in1Values = [value1, value2, value3, value4]; + } else if (unitId === UnitId.CONTROLLER_IN2) { + this.sensorValues.in2Values = [value1, value2, value3, value4]; + } else if (unitId === UnitId.CONTROLLER_IN3) { + this.sensorValues.in3Values = [value1, value2, value3, value4]; + } + } + body = body.slice(3 + valueLength, body.length); + } + this.logSensor(`sensor data : ${JSON.stringify(this.sensorValues)}`); + } + + parseResponsePdu(pdu) { + return { + blockId: pdu[IDX_PDU_CODE + 1], + result: pdu[IDX_PDU_CODE + 2], + }; + } + + getMonitorPort() { + return { + IN11: this.sensorValues.in1Values[0], + IN12: this.sensorValues.in1Values[1], + IN13: this.sensorValues.in1Values[2], + IN14: this.sensorValues.in1Values[3], + IN21: this.sensorValues.in2Values[0], + IN22: this.sensorValues.in2Values[1], + IN23: this.sensorValues.in2Values[2], + IN24: this.sensorValues.in2Values[3], + IN31: this.sensorValues.in3Values[0], + IN32: this.sensorValues.in3Values[1], + IN33: this.sensorValues.in3Values[2], + IN34: this.sensorValues.in3Values[3], + IR: this.sensorValues.irCode, + BAT: this.sensorValues.controllerBattery, + }; + } + requestLocalData() { + if (Entry.hwLite) { + if (this.executeList.length > 0) { + const executeData = this.executeList.shift(); + this.logD(this.byteArrayToHex(executeData.pdu)); + return executeData.pdu; + } + } + return null; + } + + getCheckSum(command) { + let checkSum = 0; + for (let i = 0; i < command.length; i++) { + checkSum += command[i]; + } + return checkSum & 255; + } + + /** + * pdu 길이 확인 + * 전체 길이는 pdu[3] data length + header(3) + length byte(1) + checkSum byte(1) + * @param pdu + * @return {boolean} result + */ + checkPduLength(pdu) { + const dataLength = pdu[IDX_LENGTH]; + return pdu.length >= dataLength + HEADER.length + 1 + 1; + } + + /** + * pdu 의 시작이 HEADER 와 일치하는지 확인 + * @param pdu + * @return {boolean} result + */ + checkHeader(pdu) { + if (pdu.length < HEADER.length) { + return false; + } + + for (let i = 0; i < HEADER.length; i++) { + if (HEADER[i] !== pdu[i]) { + return false; + } + } + + return true; + } + + getUnitId(port) { + switch (port) { + case 'OUT1': + return UnitId.CONTROLLER_OUT1; + case 'OUT2': + return UnitId.CONTROLLER_OUT2; + case 'OUT3': + return UnitId.CONTROLLER_OUT3; + case 'OUT12': + return UnitId.CONTROLLER_OUT12; + case 'OUT123': + return UnitId.CONTROLLER_OUT_ALL; + case 'IN1': + return UnitId.CONTROLLER_IN1; + case 'IN2': + return UnitId.CONTROLLER_IN2; + case 'IN3': + return UnitId.CONTROLLER_IN3; + } + return UnitId.CONTROLLER; + } + + /** + * 페어링 정보 요청 command (handshake 로 사용) + * @return {Array} Pairing Info command + */ + getPairingInfoCmd() { + return [FrameCode.CONNECTION, PduConnectionCode.PAIRING_INFO]; + } + + makePdu(command) { + const pdu = []; + pdu.push(...HEADER); + pdu.push(command.length); + pdu.push(...command); + pdu.push(this.getCheckSum(command)); + return pdu; + } + + requestCommand(blockId, type, params) { + if (this.pendingResponseList[blockId]) { + delete this.pendingResponseList[blockId]; + } + this.pendingResponseList[blockId] = 'executed'; + const command = this.makeCommand(blockId, type, params); + if (!command) return; + const pdu = this.makePdu(command); + this.executeList.push({ + blockId, + pdu, + }); + // Entry.hwLite.writePortData(pdu); + } + + requestExtCommand(blockId, type, params) { + if (this.pendingResponseList[blockId]) { + delete this.pendingResponseList[blockId]; + } + this.pendingResponseList[blockId] = 'executed'; + const command = this.makeCommandExt(blockId, type, params); + if (!command) return; + const pdu = this.makePdu(command); + this.executeList.push({ + blockId, + pdu, + }); + } + + generateBlockId() { + this.seqBlockId += 1; + if (this.seqBlockId > 255) { + this.seqBlockId = 1; + } + return this.seqBlockId; + } + + setLanguage() { + return { + ko: { + template: { + // motor & robot + neo_lite_motor_title: '회전모터', + neo_lite_motor_move: '회전모터 제어하기 %1 %2 %3 %4', + neo_lite_motor_move_both: '회전모터 동시에 제어하기 L %1 R %2 %3', + neo_lite_robot_move: '로봇 제어하기 %1 %2 %3 %4', + neo_lite_motor_stop: '회전모터 멈추기 %1 %2', + neo_lite_robot_stop: '로봇 멈추기 %1', + + // servo + neo_lite_servo_title: '서보모터', + neo_lite_servo_reset: '%1 서보모터 현위치를 0도로 설정하기 %2', + neo_lite_servo_angle: '서보모터 각도 바꾸기 %1 %2 %3 %4', + neo_lite_servo_angle_var: '서보모터 각도 바꾸기 %1 %2 %3 %4', + neo_lite_servo_angle_wait: '각도 바뀔때까지 기다리기 %1 %2 %3 %4', + neo_lite_servo_rotate: '서보모터 회전하기 %1 %2 %3 %4', + neo_lite_servo_stop: '서보모터 멈추기 %1 %2', + + // line tracer + neo_lite_line_tracer_title: '라인트레이서', + neo_lite_line_tracer_start: '검은색 선 따라가기 %1 %2 %3', + neo_lite_line_cross_move: '%1 교차로까지 직진하기 %2', + neo_lite_line_cross_turn: '다음 교차로에서 방향바꾸기 %1 %2', + + // auto driving + neo_lite_auto_driving_title: '자율주행', + neo_lite_auto_driving_start: '자율주행 시작하기 %1 %2 %3', + neo_lite_auto_driving_sensor_start: '%1 를 감지하여 자율주행 %2 %3', + neo_lite_auto_driving_stop: '자율주행 멈추기 %1', + + // auto parking + neo_lite_auto_parking_title: '자율주차', + neo_lite_auto_parking_start: '주차하기 %1 %2 %3', + + // line change + neo_lite_line_change_title: '차선 변경', + neo_lite_line_change_start: '%1 차로 변경하기 %2', + neo_lite_line_change_turn: '교차로에서 회전하기 %1 %2', + + // auto detect wall + neo_lite_auto_detect_wall_title: '골목주행', + neo_lite_auto_detect_wall_start: '벽 탐지하며 주행하기 %1 %2 %3', + neo_lite_auto_detect_wall_turn: '골목에서 회전하기 %1 %2', + + // led + neo_lite_led_title: 'LED', + neo_lite_led_on: 'LED 켜기 %1 %2 %3', + neo_lite_led_blink: 'LED 깜빡이기 %1 %2 %3 %4', + neo_lite_led_off: 'LED 끄기 %1 %2', + + // color led + neo_lite_color_led_title: '컬러 LED', + neo_lite_color_led_on: '컬러LED 켜기 %1 %2 %3 %4', + neo_lite_color_led_off: '컬러LED 끄기 %1 %2', + neo_lite_color_led_on_with_sensor: '컬러센서 %1 로 컬러LED %2 제어 %3', + + // set output + neo_lite_set_output_title: '출력', + neo_lite_set_output: '값 출력하기 %1 %2 %3 %4', + + // sensor + neo_lite_sensor_title: '센서', + neo_lite_sensor_in: '%1', + neo_lite_sensor_digital_in: '%1 의 %2', + neo_lite_sensor_convert: '%1 %2 %3 → %4 %5', + neo_lite_sensor_compare: '%1 %2 %3', + neo_lite_sensor_between: '%1 %2 %3 %4 %5', + neo_lite_sensor_color_compare: '%1 = %2', + neo_lite_sensor_button_pressed: '%1 %2', + + // buzzer + neo_lite_buzzer_title: '버저', + neo_lite_buzzer_start: '버저 울리기 %1 %2 %3 %4', + neo_lite_buzzer_with_sensor: '센서로 버저 울리기 %1 %2', + neo_lite_buzzer_stop: '버저 멈추기 %1', + + // lcd + neo_lite_lcd_title: 'LCD', + neo_lite_lcd_image: 'LCD에 이미지 보여주기 %1 %2 %3', + neo_lite_lcd_text: 'LCD에 텍스트 보여주기 %1 %2 %3', + + // args + neo_lite_arg_motor_speed: '%1', + neo_lite_arg_duration: '%1', + neo_lite_arg_robot_speed: '%1', + neo_lite_arg_servo_angle: '%1', + neo_lite_arg_servo_speed: '%1', + neo_lite_arg_auto_driving_speed: '%1', + neo_lite_arg_led_brightness: '%1', + neo_lite_arg_led_blink_speed: '%1', + neo_lite_arg_set_output_value: '%1', + }, + Blocks: { + neo_lite_input_1: 'IN1', + neo_lite_input_2: 'IN2', + neo_lite_input_3: 'IN3', + neo_lite_input_12: 'IN1&2', + neo_lite_input_123: 'IN1&2&3', + neo_lite_input_1_2: 'IN1&IN2', + neo_lite_input_11_12: 'IN1-1&IN1-2', + neo_lite_input_13_14: 'IN1-3&IN1-4', + neo_lite_input_21_22: 'IN2-1&IN2-2', + neo_lite_input_23_24: 'IN2-3&IN2-4', + + neo_lite_output_1: 'OUT1', + neo_lite_output_2: 'OUT2', + neo_lite_output_3: 'OUT3', + neo_lite_output_12: 'OUT1&2', + neo_lite_output_123: 'OUT1&2&3', + + neo_lite_speed_0: '0%', + neo_lite_speed_5: '5%', + neo_lite_speed_10: '10%', + neo_lite_speed_15: '15%', + neo_lite_speed_20: '20%', + neo_lite_speed_25: '25%', + neo_lite_speed_30: '30%', + neo_lite_speed_35: '35%', + neo_lite_speed_40: '40%', + neo_lite_speed_45: '45%', + neo_lite_speed_50: '50%', + neo_lite_speed_55: '55%', + neo_lite_speed_60: '60%', + neo_lite_speed_65: '65%', + neo_lite_speed_70: '70%', + neo_lite_speed_75: '75%', + neo_lite_speed_80: '80%', + neo_lite_speed_85: '85%', + neo_lite_speed_90: '90%', + neo_lite_speed_95: '95%', + neo_lite_speed_100: '100%', + + neo_lite_duration_c: '계속', + neo_lite_duration_0: '0초', + neo_lite_duration_1: '1초', + neo_lite_duration_2: '2초', + neo_lite_duration_3: '3초', + neo_lite_duration_4: '4초', + neo_lite_duration_5: '5초', + neo_lite_duration_6: '6초', + neo_lite_duration_7: '7초', + neo_lite_duration_8: '8초', + neo_lite_duration_9: '9초', + + neo_lite_compare_gt: '≥', + neo_lite_compare_g: '>', + neo_lite_compare_e: '=', + neo_lite_compare_l: '<', + neo_lite_compare_lt: '≤', + + neo_lite_turn_direction_l: '좌회전', + neo_lite_turn_direction_r: '우회전', + neo_lite_turn_direction_u: 'U턴', + + neo_lite_motor_out_l: 'L모터', + neo_lite_motor_out_r: 'R모터', + neo_lite_motor_out_lr: 'L/R모터', + + neo_lite_motor_speed_n100: '-100%', + neo_lite_motor_speed_n95: '-95%', + neo_lite_motor_speed_n90: '-90%', + neo_lite_motor_speed_n85: '-85%', + neo_lite_motor_speed_n80: '-80%', + neo_lite_motor_speed_n75: '-75%', + neo_lite_motor_speed_n70: '-70%', + neo_lite_motor_speed_n65: '-65%', + neo_lite_motor_speed_n60: '-60%', + neo_lite_motor_speed_n55: '-55%', + neo_lite_motor_speed_n50: '-50%', + neo_lite_motor_speed_n45: '-45%', + neo_lite_motor_speed_n40: '-40%', + neo_lite_motor_speed_n35: '-35%', + neo_lite_motor_speed_n30: '-30%', + neo_lite_motor_speed_n25: '-25%', + neo_lite_motor_speed_n20: '-20%', + neo_lite_motor_speed_n15: '-15%', + neo_lite_motor_speed_n10: '-10%', + neo_lite_motor_speed_n5: '-5%', + neo_lite_motor_speed_0: '0%', + neo_lite_motor_speed_5: '5%', + neo_lite_motor_speed_10: '10%', + neo_lite_motor_speed_15: '15%', + neo_lite_motor_speed_20: '20%', + neo_lite_motor_speed_25: '25%', + neo_lite_motor_speed_30: '30%', + neo_lite_motor_speed_35: '35%', + neo_lite_motor_speed_40: '40%', + neo_lite_motor_speed_45: '45%', + neo_lite_motor_speed_50: '50%', + neo_lite_motor_speed_55: '55%', + neo_lite_motor_speed_60: '60%', + neo_lite_motor_speed_65: '65%', + neo_lite_motor_speed_70: '70%', + neo_lite_motor_speed_75: '75%', + neo_lite_motor_speed_80: '80%', + neo_lite_motor_speed_85: '85%', + neo_lite_motor_speed_90: '90%', + neo_lite_motor_speed_95: '95%', + neo_lite_motor_speed_100: '100%', + + neo_lite_robot_direction_f: '앞으로', + neo_lite_robot_direction_b: '뒤로', + neo_lite_robot_direction_l: '왼쪽으로', + neo_lite_robot_direction_r: '오른쪽으로', + neo_lite_robot_direction_tl: '제자리왼쪽', + neo_lite_robot_direction_tr: '제자리오른쪽', + + neo_lite_servo_angle_n360: '-360도', + neo_lite_servo_angle_n350: '-350도', + neo_lite_servo_angle_n340: '-340도', + neo_lite_servo_angle_n330: '-330도', + neo_lite_servo_angle_n320: '-320도', + neo_lite_servo_angle_n310: '-310도', + neo_lite_servo_angle_n300: '-300도', + neo_lite_servo_angle_n290: '-290도', + neo_lite_servo_angle_n280: '-280도', + neo_lite_servo_angle_n270: '-270도', + neo_lite_servo_angle_n260: '-260도', + neo_lite_servo_angle_n250: '-250도', + neo_lite_servo_angle_n240: '-240도', + neo_lite_servo_angle_n230: '-230도', + neo_lite_servo_angle_n220: '-220도', + neo_lite_servo_angle_n210: '-210도', + neo_lite_servo_angle_n200: '-200도', + neo_lite_servo_angle_n190: '-190도', + neo_lite_servo_angle_n180: '-180도', + neo_lite_servo_angle_n170: '-170도', + neo_lite_servo_angle_n160: '-160도', + neo_lite_servo_angle_n150: '-150도', + neo_lite_servo_angle_n140: '-140도', + neo_lite_servo_angle_n130: '-130도', + neo_lite_servo_angle_n120: '-120도', + neo_lite_servo_angle_n110: '-110도', + neo_lite_servo_angle_n100: '-100도', + neo_lite_servo_angle_n90: '-90도', + neo_lite_servo_angle_n80: '-80도', + neo_lite_servo_angle_n70: '-70도', + neo_lite_servo_angle_n60: '-60도', + neo_lite_servo_angle_n50: '-50도', + neo_lite_servo_angle_n40: '-40도', + neo_lite_servo_angle_n30: '-30도', + neo_lite_servo_angle_n20: '-20도', + neo_lite_servo_angle_n10: '-10도', + neo_lite_servo_angle_0: '0도', + neo_lite_servo_angle_10: '10도', + neo_lite_servo_angle_20: '20도', + neo_lite_servo_angle_30: '30도', + neo_lite_servo_angle_40: '40도', + neo_lite_servo_angle_50: '50도', + neo_lite_servo_angle_60: '60도', + neo_lite_servo_angle_70: '70도', + neo_lite_servo_angle_80: '80도', + neo_lite_servo_angle_90: '90도', + neo_lite_servo_angle_100: '100도', + neo_lite_servo_angle_110: '110도', + neo_lite_servo_angle_120: '120도', + neo_lite_servo_angle_130: '130도', + neo_lite_servo_angle_140: '140도', + neo_lite_servo_angle_150: '150도', + neo_lite_servo_angle_160: '160도', + neo_lite_servo_angle_170: '170도', + neo_lite_servo_angle_180: '180도', + neo_lite_servo_angle_190: '190도', + neo_lite_servo_angle_200: '200도', + neo_lite_servo_angle_210: '210도', + neo_lite_servo_angle_220: '220도', + neo_lite_servo_angle_230: '230도', + neo_lite_servo_angle_240: '240도', + neo_lite_servo_angle_250: '250도', + neo_lite_servo_angle_260: '260도', + neo_lite_servo_angle_270: '270도', + neo_lite_servo_angle_280: '280도', + neo_lite_servo_angle_290: '290도', + neo_lite_servo_angle_300: '300도', + neo_lite_servo_angle_310: '310도', + neo_lite_servo_angle_320: '320도', + neo_lite_servo_angle_330: '330도', + neo_lite_servo_angle_340: '340도', + neo_lite_servo_angle_350: '350도', + neo_lite_servo_angle_360: '360도', + + neo_lite_servo_direction_f: '앞으로', + neo_lite_servo_direction_b: '뒤로', + + neo_lite_line_cross_move_1: '1번째', + neo_lite_line_cross_move_2: '2번째', + neo_lite_line_cross_move_3: '3번째', + neo_lite_line_cross_move_4: '4번째', + neo_lite_line_cross_move_5: '5번째', + neo_lite_line_cross_move_6: '6번째', + neo_lite_line_cross_move_7: '7번째', + neo_lite_line_cross_move_8: '8번째', + neo_lite_line_cross_move_9: '9번째', + neo_lite_line_cross_move_10: '10번째', + + neo_lite_line_cross_turn_direction_l: '좌회전', + neo_lite_line_cross_turn_direction_r: '우회전', + neo_lite_line_cross_turn_direction_u: 'U턴', + + neo_lite_auto_driving_speed_in3: 'IN3', + + neo_lite_auto_parking_which_l: '왼쪽에', + neo_lite_auto_parking_which_r: '오른쪽에', + + neo_lite_auto_parking_direction_b: '후면주차', + neo_lite_auto_parking_direction_s: '평행주차', + + neo_lite_line_change_direction_l: '왼쪽으로', + neo_lite_line_change_direction_r: '오른쪽으로', + + neo_lite_line_change_turn_direction_l: '좌회전', + neo_lite_line_change_turn_direction_r: '우회전', + neo_lite_line_change_turn_direction_u: 'U턴', + + neo_lite_led_brightness_0: '0%', + neo_lite_led_brightness_5: '5%', + neo_lite_led_brightness_10: '10%', + neo_lite_led_brightness_15: '15%', + neo_lite_led_brightness_20: '20%', + neo_lite_led_brightness_25: '25%', + neo_lite_led_brightness_30: '30%', + neo_lite_led_brightness_35: '35%', + neo_lite_led_brightness_40: '40%', + neo_lite_led_brightness_45: '45%', + neo_lite_led_brightness_50: '50%', + neo_lite_led_brightness_55: '55%', + neo_lite_led_brightness_60: '60%', + neo_lite_led_brightness_65: '65%', + neo_lite_led_brightness_70: '70%', + neo_lite_led_brightness_75: '75%', + neo_lite_led_brightness_80: '80%', + neo_lite_led_brightness_85: '85%', + neo_lite_led_brightness_90: '90%', + neo_lite_led_brightness_95: '95%', + neo_lite_led_brightness_100: '100%', + + neo_lite_led_blink_speed_1: '1단계', + neo_lite_led_blink_speed_2: '2단계', + neo_lite_led_blink_speed_3: '3단계', + neo_lite_led_blink_speed_4: '4단계', + neo_lite_led_blink_speed_5: '5단계', + + neo_lite_set_output_value_0: '0', + neo_lite_set_output_value_5: '5', + neo_lite_set_output_value_10: '10', + neo_lite_set_output_value_15: '15', + neo_lite_set_output_value_20: '20', + neo_lite_set_output_value_25: '25', + neo_lite_set_output_value_30: '30', + neo_lite_set_output_value_35: '35', + neo_lite_set_output_value_40: '40', + neo_lite_set_output_value_45: '45', + neo_lite_set_output_value_50: '50', + neo_lite_set_output_value_55: '55', + neo_lite_set_output_value_60: '60', + neo_lite_set_output_value_65: '65', + neo_lite_set_output_value_70: '70', + neo_lite_set_output_value_75: '75', + neo_lite_set_output_value_80: '80', + neo_lite_set_output_value_85: '85', + neo_lite_set_output_value_90: '90', + neo_lite_set_output_value_95: '95', + neo_lite_set_output_value_100: '100', + neo_lite_set_output_value_105: '105', + neo_lite_set_output_value_110: '110', + neo_lite_set_output_value_115: '115', + neo_lite_set_output_value_120: '120', + neo_lite_set_output_value_125: '125', + neo_lite_set_output_value_130: '130', + neo_lite_set_output_value_135: '135', + neo_lite_set_output_value_140: '140', + neo_lite_set_output_value_145: '145', + neo_lite_set_output_value_150: '150', + neo_lite_set_output_value_155: '155', + neo_lite_set_output_value_160: '160', + neo_lite_set_output_value_165: '165', + neo_lite_set_output_value_170: '170', + neo_lite_set_output_value_175: '175', + neo_lite_set_output_value_180: '180', + neo_lite_set_output_value_185: '185', + neo_lite_set_output_value_190: '190', + neo_lite_set_output_value_195: '195', + neo_lite_set_output_value_200: '200', + neo_lite_set_output_value_205: '205', + neo_lite_set_output_value_210: '210', + neo_lite_set_output_value_215: '215', + neo_lite_set_output_value_220: '220', + neo_lite_set_output_value_225: '225', + neo_lite_set_output_value_230: '230', + neo_lite_set_output_value_235: '235', + neo_lite_set_output_value_240: '240', + neo_lite_set_output_value_245: '245', + neo_lite_set_output_value_250: '250', + neo_lite_set_output_value_255: '255', + + neo_lite_sensor_in_digital_1: '1번', + neo_lite_sensor_in_digital_2: '2번', + neo_lite_sensor_in_digital_3: '3번', + neo_lite_sensor_in_digital_4: '4번', + + neo_lite_color_black: '검정', + neo_lite_color_white: '흰색', + neo_lite_color_red: '빨강', + neo_lite_color_yellow: '노랑', + neo_lite_color_green: '녹색', + neo_lite_color_blue: '파랑', + + neo_lite_button_1: '버튼1', + neo_lite_button_2: '버튼2', + neo_lite_button_3: '버튼3', + neo_lite_button_4: '버튼4', + + neo_lite_button_on: 'ON', + neo_lite_button_off: 'OFF', + + neo_lite_buzzer_octave_1: '1옥타브', + neo_lite_buzzer_octave_2: '2옥타브', + neo_lite_buzzer_octave_3: '3옥타브', + neo_lite_buzzer_octave_4: '4옥타브', + neo_lite_buzzer_octave_5: '5옥타브', + neo_lite_buzzer_octave_6: '6옥타브', + + neo_lite_buzzer_do: '도', + neo_lite_buzzer_do_sharp: '도#', + neo_lite_buzzer_re: '레', + neo_lite_buzzer_re_sharp: '레#', + neo_lite_buzzer_mi: '미', + neo_lite_buzzer_fa: '파', + neo_lite_buzzer_fa_sharp: '파#', + neo_lite_buzzer_sol: '솔', + neo_lite_buzzer_sol_sharp: '솔#', + neo_lite_buzzer_la: '라', + neo_lite_buzzer_la_sharp: '라#', + neo_lite_buzzer_ti: '시', + + neo_lite_buzzer_whole_note: '온음표', + neo_lite_buzzer_half_note: '2분 음표', + neo_lite_buzzer_quarter_note: '4분 음표', + neo_lite_buzzer_8th_note: '8분 음표', + + neo_lite_lcd_image_1: '1', + neo_lite_lcd_image_2: '2', + neo_lite_lcd_image_3: '3', + neo_lite_lcd_image_4: '4', + neo_lite_lcd_image_5: '5', + neo_lite_lcd_image_6: '6', + neo_lite_lcd_image_7: '7', + neo_lite_lcd_image_8: '8', + neo_lite_lcd_image_9: '9', + neo_lite_lcd_image_10: '10', + neo_lite_lcd_image_11: '11', + neo_lite_lcd_image_12: '12', + neo_lite_lcd_image_13: '13', + neo_lite_lcd_image_14: '14', + neo_lite_lcd_image_15: '15', + }, + }, + en: { + // en.js에 작성하던 내용 + template: { + // motor & robot + // motor & robot + neo_lite_motor_title: 'Motor', + neo_lite_motor_move: 'Move motor %1 %2 %3 %4', + neo_lite_motor_move_both: 'Move both motor L %1 R %2 %3', + neo_lite_robot_move: 'Move robot %1 %2 %3 %4', + neo_lite_motor_stop: 'Stop motor %1 %2', + neo_lite_robot_stop: 'Stop robot %1', + + // servo + neo_lite_servo_title: 'Servo motor', + neo_lite_servo_reset: 'Reset the current position of %1 servo motor to 0 degree %2', + neo_lite_servo_angle: 'Change servo angle %1 %2 %3 %4', + neo_lite_servo_angle_var: 'Change servo angle %1 %2 %3 %4', + neo_lite_servo_angle_wait: 'Wait to change servo angle %1 %2 %3 %4', + neo_lite_servo_rotate: 'Rotate servo motor %1 %2 %3 %4', + neo_lite_servo_stop: 'Stop servo motor %1 %2', + + // line tracer + neo_lite_line_tracer_title: 'Line tracer', + neo_lite_line_tracer_start: 'Start line tracer with black line %1 %2 %3', + neo_lite_line_cross_move: 'Keep moving to the %1 intersection %2', + neo_lite_line_cross_turn: 'Turn at the next intersection %1 %2', + + // auto driving + neo_lite_auto_driving_title: 'Self-driving', + neo_lite_auto_driving_start: 'Start self-driving %1 %2 %3', + neo_lite_auto_driving_sensor_start: 'Start self-driving with %1 %2 %3', + neo_lite_auto_driving_stop: 'Stop self-driving %1', + + // auto parking + neo_lite_auto_parking_title: 'Auto parking', + neo_lite_auto_parking_start: 'Start auto parking %1 %2 %3', + + // line change + neo_lite_line_change_title: 'Lane change', + neo_lite_line_change_start: 'Change Lane %1 %2', + neo_lite_line_change_turn: 'Turn at the intersection %1 %2', + + // auto detect wall + neo_lite_auto_detect_wall_title: 'Alley driving', + neo_lite_auto_detect_wall_start: 'Start alley driving %1 %2 %3', + neo_lite_auto_detect_wall_turn: 'Turn in the alley %1 %2', + + // led + neo_lite_led_title: 'LED', + neo_lite_led_on: 'Turn on the LED %1 %2 %3', + neo_lite_led_blink: 'Blink the LED %1 %2 %3 %4', + neo_lite_led_off: 'Turn off the LED %1 %2', + + // color led + neo_lite_color_led_title: 'Color LED', + neo_lite_color_led_on: 'Turn on the color LED %1 %2 %3 %4', + neo_lite_color_led_off: 'Turn off the color LED %1 %2', + neo_lite_color_led_on_with_sensor: 'Turn on the color LED %2 with color sensor %1 %3', + + // set output + neo_lite_set_output_title: 'Set output', + neo_lite_set_output: 'Set output %1 %2 %3 %4', + + // sensor + neo_lite_sensor_title: 'Sensor', + neo_lite_sensor_in: '%1', + neo_lite_sensor_digital_in: '%1 %2', + neo_lite_sensor_convert: '%1 %2 %3 → %4 %5', + neo_lite_sensor_compare: '%1 %2 %3', + neo_lite_sensor_between: '%1 %2 %3 %4 %5', + neo_lite_sensor_color_compare: '%1 = %2', + neo_lite_sensor_button_pressed: '%1 %2', + + // buzzer + neo_lite_buzzer_title: 'Buzzer', + neo_lite_buzzer_start: 'Buzzer %1 %2 %3 %4', + neo_lite_buzzer_with_sensor: 'Buzzer by sensor value %1 %2', + neo_lite_buzzer_stop: 'Stop the buzzer %1', + + // lcd + neo_lite_lcd_title: 'LCD', + neo_lite_lcd_image: 'Show image on LCD %1 %2 %3', + neo_lite_lcd_text: 'Show text on LCD %1 %2 %3', + + // args + neo_lite_arg_motor_speed: '%1', + neo_lite_arg_duration: '%1', + neo_lite_arg_robot_speed: '%1', + neo_lite_arg_servo_angle: '%1', + neo_lite_arg_servo_speed: '%1', + neo_lite_arg_auto_driving_speed: '%1', + neo_lite_arg_led_brightness: '%1', + neo_lite_arg_led_blink_speed: '%1', + neo_lite_arg_set_output_value: '%1', + }, + Blocks: { + neo_lite_input_1: 'IN1', + neo_lite_input_2: 'IN2', + neo_lite_input_3: 'IN3', + neo_lite_input_12: 'IN1&2', + neo_lite_input_123: 'IN1&2&3', + neo_lite_input_1_2: 'IN1&IN2', + neo_lite_input_11_12: 'IN1-1&IN1-2', + neo_lite_input_13_14: 'IN1-3&IN1-4', + neo_lite_input_21_22: 'IN2-1&IN2-2', + neo_lite_input_23_24: 'IN2-3&IN2-4', + + neo_lite_output_1: 'OUT1', + neo_lite_output_2: 'OUT2', + neo_lite_output_3: 'OUT3', + neo_lite_output_12: 'OUT1&2', + neo_lite_output_123: 'OUT1&2&3', + + neo_lite_speed_0: '0%', + neo_lite_speed_5: '5%', + neo_lite_speed_10: '10%', + neo_lite_speed_15: '15%', + neo_lite_speed_20: '20%', + neo_lite_speed_25: '25%', + neo_lite_speed_30: '30%', + neo_lite_speed_35: '35%', + neo_lite_speed_40: '40%', + neo_lite_speed_45: '45%', + neo_lite_speed_50: '50%', + neo_lite_speed_55: '55%', + neo_lite_speed_60: '60%', + neo_lite_speed_65: '65%', + neo_lite_speed_70: '70%', + neo_lite_speed_75: '75%', + neo_lite_speed_80: '80%', + neo_lite_speed_85: '85%', + neo_lite_speed_90: '90%', + neo_lite_speed_95: '95%', + neo_lite_speed_100: '100%', + + neo_lite_duration_c: 'constantly', + neo_lite_duration_0: '0 second', + neo_lite_duration_1: '1 second', + neo_lite_duration_2: '2 second', + neo_lite_duration_3: '3 second', + neo_lite_duration_4: '4 second', + neo_lite_duration_5: '5 second', + neo_lite_duration_6: '6 second', + neo_lite_duration_7: '7 second', + neo_lite_duration_8: '8 second', + neo_lite_duration_9: '9 second', + + neo_lite_compare_gt: '≥', + neo_lite_compare_g: '>', + neo_lite_compare_e: '=', + neo_lite_compare_l: '<', + neo_lite_compare_lt: '≤', + + neo_lite_turn_direction_l: 'left', + neo_lite_turn_direction_r: 'right', + neo_lite_turn_direction_u: 'U-turn', + + neo_lite_motor_out_l: 'left', + neo_lite_motor_out_r: 'right', + neo_lite_motor_out_lr: 'both', + + neo_lite_motor_speed_n100: '-100%', + neo_lite_motor_speed_n95: '-95%', + neo_lite_motor_speed_n90: '-90%', + neo_lite_motor_speed_n85: '-85%', + neo_lite_motor_speed_n80: '-80%', + neo_lite_motor_speed_n75: '-75%', + neo_lite_motor_speed_n70: '-70%', + neo_lite_motor_speed_n65: '-65%', + neo_lite_motor_speed_n60: '-60%', + neo_lite_motor_speed_n55: '-55%', + neo_lite_motor_speed_n50: '-50%', + neo_lite_motor_speed_n45: '-45%', + neo_lite_motor_speed_n40: '-40%', + neo_lite_motor_speed_n35: '-35%', + neo_lite_motor_speed_n30: '-30%', + neo_lite_motor_speed_n25: '-25%', + neo_lite_motor_speed_n20: '-20%', + neo_lite_motor_speed_n15: '-15%', + neo_lite_motor_speed_n10: '-10%', + neo_lite_motor_speed_n5: '-5%', + neo_lite_motor_speed_0: '0%', + neo_lite_motor_speed_5: '5%', + neo_lite_motor_speed_10: '10%', + neo_lite_motor_speed_15: '15%', + neo_lite_motor_speed_20: '20%', + neo_lite_motor_speed_25: '25%', + neo_lite_motor_speed_30: '30%', + neo_lite_motor_speed_35: '35%', + neo_lite_motor_speed_40: '40%', + neo_lite_motor_speed_45: '45%', + neo_lite_motor_speed_50: '50%', + neo_lite_motor_speed_55: '55%', + neo_lite_motor_speed_60: '60%', + neo_lite_motor_speed_65: '65%', + neo_lite_motor_speed_70: '70%', + neo_lite_motor_speed_75: '75%', + neo_lite_motor_speed_80: '80%', + neo_lite_motor_speed_85: '85%', + neo_lite_motor_speed_90: '90%', + neo_lite_motor_speed_95: '95%', + neo_lite_motor_speed_100: '100%', + + neo_lite_robot_direction_f: 'forward', + neo_lite_robot_direction_b: 'backward', + neo_lite_robot_direction_l: 'left', + neo_lite_robot_direction_r: 'right', + neo_lite_robot_direction_tl: 'left in place', + neo_lite_robot_direction_tr: 'right in place', + + neo_lite_servo_angle_n360: '-360 degree', + neo_lite_servo_angle_n350: '-350 degree', + neo_lite_servo_angle_n340: '-340 degree', + neo_lite_servo_angle_n330: '-330 degree', + neo_lite_servo_angle_n320: '-320 degree', + neo_lite_servo_angle_n310: '-310 degree', + neo_lite_servo_angle_n300: '-300 degree', + neo_lite_servo_angle_n290: '-290 degree', + neo_lite_servo_angle_n280: '-280 degree', + neo_lite_servo_angle_n270: '-270 degree', + neo_lite_servo_angle_n260: '-260 degree', + neo_lite_servo_angle_n250: '-250 degree', + neo_lite_servo_angle_n240: '-240 degree', + neo_lite_servo_angle_n230: '-230 degree', + neo_lite_servo_angle_n220: '-220 degree', + neo_lite_servo_angle_n210: '-210 degree', + neo_lite_servo_angle_n200: '-200 degree', + neo_lite_servo_angle_n190: '-190 degree', + neo_lite_servo_angle_n180: '-180 degree', + neo_lite_servo_angle_n170: '-170 degree', + neo_lite_servo_angle_n160: '-160 degree', + neo_lite_servo_angle_n150: '-150 degree', + neo_lite_servo_angle_n140: '-140 degree', + neo_lite_servo_angle_n130: '-130 degree', + neo_lite_servo_angle_n120: '-120 degree', + neo_lite_servo_angle_n110: '-110 degree', + neo_lite_servo_angle_n100: '-100 degree', + neo_lite_servo_angle_n90: '-90 degree', + neo_lite_servo_angle_n80: '-80 degree', + neo_lite_servo_angle_n70: '-70 degree', + neo_lite_servo_angle_n60: '-60 degree', + neo_lite_servo_angle_n50: '-50 degree', + neo_lite_servo_angle_n40: '-40 degree', + neo_lite_servo_angle_n30: '-30 degree', + neo_lite_servo_angle_n20: '-20 degree', + neo_lite_servo_angle_n10: '-10 degree', + neo_lite_servo_angle_0: '0 degree', + neo_lite_servo_angle_10: '10 degree', + neo_lite_servo_angle_20: '20 degree', + neo_lite_servo_angle_30: '30 degree', + neo_lite_servo_angle_40: '40 degree', + neo_lite_servo_angle_50: '50 degree', + neo_lite_servo_angle_60: '60 degree', + neo_lite_servo_angle_70: '70 degree', + neo_lite_servo_angle_80: '80 degree', + neo_lite_servo_angle_90: '90 degree', + neo_lite_servo_angle_100: '100 degree', + neo_lite_servo_angle_110: '110 degree', + neo_lite_servo_angle_120: '120 degree', + neo_lite_servo_angle_130: '130 degree', + neo_lite_servo_angle_140: '140 degree', + neo_lite_servo_angle_150: '150 degree', + neo_lite_servo_angle_160: '160 degree', + neo_lite_servo_angle_170: '170 degree', + neo_lite_servo_angle_180: '180 degree', + neo_lite_servo_angle_190: '190 degree', + neo_lite_servo_angle_200: '200 degree', + neo_lite_servo_angle_210: '210 degree', + neo_lite_servo_angle_220: '220 degree', + neo_lite_servo_angle_230: '230 degree', + neo_lite_servo_angle_240: '240 degree', + neo_lite_servo_angle_250: '250 degree', + neo_lite_servo_angle_260: '260 degree', + neo_lite_servo_angle_270: '270 degree', + neo_lite_servo_angle_280: '280 degree', + neo_lite_servo_angle_290: '290 degree', + neo_lite_servo_angle_300: '300 degree', + neo_lite_servo_angle_310: '310 degree', + neo_lite_servo_angle_320: '320 degree', + neo_lite_servo_angle_330: '330 degree', + neo_lite_servo_angle_340: '340 degree', + neo_lite_servo_angle_350: '350 degree', + neo_lite_servo_angle_360: '360 degree', + + neo_lite_servo_direction_f: 'forward', + neo_lite_servo_direction_b: 'backward', + + neo_lite_line_cross_move_1: '1st', + neo_lite_line_cross_move_2: '2nd', + neo_lite_line_cross_move_3: '3rd', + neo_lite_line_cross_move_4: '4th', + neo_lite_line_cross_move_5: '5th', + neo_lite_line_cross_move_6: '6th', + neo_lite_line_cross_move_7: '7th', + neo_lite_line_cross_move_8: '8th', + neo_lite_line_cross_move_9: '9th', + neo_lite_line_cross_move_10: '10th', + + neo_lite_line_cross_turn_direction_l: 'to left', + neo_lite_line_cross_turn_direction_r: 'to right', + neo_lite_line_cross_turn_direction_u: 'U-turn', + + neo_lite_auto_driving_speed_in3: 'IN3', + + neo_lite_auto_parking_which_l: 'to left', + neo_lite_auto_parking_which_r: 'to right', + + neo_lite_auto_parking_direction_b: 'rear parking', + neo_lite_auto_parking_direction_s: 'parallel parking', + + neo_lite_line_change_direction_l: 'to left', + neo_lite_line_change_direction_r: 'to right', + + neo_lite_line_change_turn_direction_l: 'to left', + neo_lite_line_change_turn_direction_r: 'to right', + neo_lite_line_change_turn_direction_u: 'U-turn', + + neo_lite_led_brightness_0: '0%', + neo_lite_led_brightness_5: '5%', + neo_lite_led_brightness_10: '10%', + neo_lite_led_brightness_15: '15%', + neo_lite_led_brightness_20: '20%', + neo_lite_led_brightness_25: '25%', + neo_lite_led_brightness_30: '30%', + neo_lite_led_brightness_35: '35%', + neo_lite_led_brightness_40: '40%', + neo_lite_led_brightness_45: '45%', + neo_lite_led_brightness_50: '50%', + neo_lite_led_brightness_55: '55%', + neo_lite_led_brightness_60: '60%', + neo_lite_led_brightness_65: '65%', + neo_lite_led_brightness_70: '70%', + neo_lite_led_brightness_75: '75%', + neo_lite_led_brightness_80: '80%', + neo_lite_led_brightness_85: '85%', + neo_lite_led_brightness_90: '90%', + neo_lite_led_brightness_95: '95%', + neo_lite_led_brightness_100: '100%', + + neo_lite_led_blink_speed_1: '1 step', + neo_lite_led_blink_speed_2: '2 step', + neo_lite_led_blink_speed_3: '3 step', + neo_lite_led_blink_speed_4: '4 step', + neo_lite_led_blink_speed_5: '5 step', + + neo_lite_set_output_value_0: '0', + neo_lite_set_output_value_5: '5', + neo_lite_set_output_value_10: '10', + neo_lite_set_output_value_15: '15', + neo_lite_set_output_value_20: '20', + neo_lite_set_output_value_25: '25', + neo_lite_set_output_value_30: '30', + neo_lite_set_output_value_35: '35', + neo_lite_set_output_value_40: '40', + neo_lite_set_output_value_45: '45', + neo_lite_set_output_value_50: '50', + neo_lite_set_output_value_55: '55', + neo_lite_set_output_value_60: '60', + neo_lite_set_output_value_65: '65', + neo_lite_set_output_value_70: '70', + neo_lite_set_output_value_75: '75', + neo_lite_set_output_value_80: '80', + neo_lite_set_output_value_85: '85', + neo_lite_set_output_value_90: '90', + neo_lite_set_output_value_95: '95', + neo_lite_set_output_value_100: '100', + neo_lite_set_output_value_105: '105', + neo_lite_set_output_value_110: '110', + neo_lite_set_output_value_115: '115', + neo_lite_set_output_value_120: '120', + neo_lite_set_output_value_125: '125', + neo_lite_set_output_value_130: '130', + neo_lite_set_output_value_135: '135', + neo_lite_set_output_value_140: '140', + neo_lite_set_output_value_145: '145', + neo_lite_set_output_value_150: '150', + neo_lite_set_output_value_155: '155', + neo_lite_set_output_value_160: '160', + neo_lite_set_output_value_165: '165', + neo_lite_set_output_value_170: '170', + neo_lite_set_output_value_175: '175', + neo_lite_set_output_value_180: '180', + neo_lite_set_output_value_185: '185', + neo_lite_set_output_value_190: '190', + neo_lite_set_output_value_195: '195', + neo_lite_set_output_value_200: '200', + neo_lite_set_output_value_205: '205', + neo_lite_set_output_value_210: '210', + neo_lite_set_output_value_215: '215', + neo_lite_set_output_value_220: '220', + neo_lite_set_output_value_225: '225', + neo_lite_set_output_value_230: '230', + neo_lite_set_output_value_235: '235', + neo_lite_set_output_value_240: '240', + neo_lite_set_output_value_245: '245', + neo_lite_set_output_value_250: '250', + neo_lite_set_output_value_255: '255', + + neo_lite_sensor_in_digital_1: '1st', + neo_lite_sensor_in_digital_2: '2nd', + neo_lite_sensor_in_digital_3: '3rd', + neo_lite_sensor_in_digital_4: '4th', + + neo_lite_color_black: 'black', + neo_lite_color_white: 'white', + neo_lite_color_red: 'red', + neo_lite_color_yellow: 'yellow', + neo_lite_color_green: 'green', + neo_lite_color_blue: 'blue', + + neo_lite_button_1: 'button 1', + neo_lite_button_2: 'button 2', + neo_lite_button_3: 'button 3', + neo_lite_button_4: 'button 4', + + neo_lite_button_on: 'ON', + neo_lite_button_off: 'OFF', + + neo_lite_buzzer_octave_1: '1 octave', + neo_lite_buzzer_octave_2: '2 octave', + neo_lite_buzzer_octave_3: '3 octave', + neo_lite_buzzer_octave_4: '4 octave', + neo_lite_buzzer_octave_5: '5 octave', + neo_lite_buzzer_octave_6: '6 octave', + + neo_lite_buzzer_do: 'Do', + neo_lite_buzzer_do_sharp: 'Do#', + neo_lite_buzzer_re: 'Re', + neo_lite_buzzer_re_sharp: 'Re#', + neo_lite_buzzer_mi: 'Mi', + neo_lite_buzzer_fa: 'Fa', + neo_lite_buzzer_fa_sharp: 'Fa#', + neo_lite_buzzer_sol: 'So', + neo_lite_buzzer_sol_sharp: 'So#', + neo_lite_buzzer_la: 'La', + neo_lite_buzzer_la_sharp: 'La#', + neo_lite_buzzer_ti: 'Si', + + neo_lite_buzzer_whole_note: 'whole note', + neo_lite_buzzer_half_note: 'a half note', + neo_lite_buzzer_quarter_note: 'a quarter note', + neo_lite_buzzer_8th_note: 'a eighth note', + + neo_lite_lcd_image_1: '1', + neo_lite_lcd_image_2: '2', + neo_lite_lcd_image_3: '3', + neo_lite_lcd_image_4: '4', + neo_lite_lcd_image_5: '5', + neo_lite_lcd_image_6: '6', + neo_lite_lcd_image_7: '7', + neo_lite_lcd_image_8: '8', + neo_lite_lcd_image_9: '9', + neo_lite_lcd_image_10: '10', + neo_lite_lcd_image_11: '11', + neo_lite_lcd_image_12: '12', + neo_lite_lcd_image_13: '13', + neo_lite_lcd_image_14: '14', + neo_lite_lcd_image_15: '15', + }, + }, // + }; + } + + getBlocks() { + return { + /** + * 회전모터 + */ + neo_lite_motor_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_motor_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_motor_title', + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_motor_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_out_l, 1], + [Lang.Blocks.neo_lite_motor_out_r, 2], + [Lang.Blocks.neo_lite_motor_out_lr, 0], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_95, '95'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_85, '85'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_75, '75'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_65, '65'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_55, '55'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_45, '45'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_35, '35'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_25, '25'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_15, '15'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_5, '5'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_motor_speed_n5, '-5'], + [Lang.Blocks.neo_lite_motor_speed_n10, '-10'], + [Lang.Blocks.neo_lite_motor_speed_n15, '-15'], + [Lang.Blocks.neo_lite_motor_speed_n20, '-20'], + [Lang.Blocks.neo_lite_motor_speed_n25, '-25'], + [Lang.Blocks.neo_lite_motor_speed_n30, '-30'], + [Lang.Blocks.neo_lite_motor_speed_n35, '-35'], + [Lang.Blocks.neo_lite_motor_speed_n40, '-40'], + [Lang.Blocks.neo_lite_motor_speed_n45, '-45'], + [Lang.Blocks.neo_lite_motor_speed_n50, '-50'], + [Lang.Blocks.neo_lite_motor_speed_n55, '-55'], + [Lang.Blocks.neo_lite_motor_speed_n60, '-60'], + [Lang.Blocks.neo_lite_motor_speed_n65, '-65'], + [Lang.Blocks.neo_lite_motor_speed_n70, '-70'], + [Lang.Blocks.neo_lite_motor_speed_n75, '-75'], + [Lang.Blocks.neo_lite_motor_speed_n80, '-80'], + [Lang.Blocks.neo_lite_motor_speed_n85, '-85'], + [Lang.Blocks.neo_lite_motor_speed_n90, '-90'], + [Lang.Blocks.neo_lite_motor_speed_n95, '-95'], + [Lang.Blocks.neo_lite_motor_speed_n100, '-100'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_motor_move', + }, + paramsKeyMap: { + DC: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const dc = script.getNumberField('DC', script); + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const dc = script.getNumberField('DC', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE, [dc, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_motor_move_both: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + { + type: 'neo_lite_arg_motor_speed', + }, + { + type: 'neo_lite_arg_motor_speed', + }, + null, + ], + type: 'neo_lite_motor_move_both', + }, + paramsKeyMap: { + SPEED_L: 0, + SPEED_R: 1, + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const speedL = script.getNumberValue('SPEED_L', script); + const speedR = script.getNumberValue('SPEED_R', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [speedL, speedR]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_robot_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_robot_direction_f, 1], + [Lang.Blocks.neo_lite_robot_direction_b, 2], + [Lang.Blocks.neo_lite_robot_direction_l, 3], + [Lang.Blocks.neo_lite_robot_direction_r, 4], + [Lang.Blocks.neo_lite_robot_direction_tl, 5], + [Lang.Blocks.neo_lite_robot_direction_tr, 6], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_95, '95'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_85, '85'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_75, '75'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_65, '65'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_55, '55'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_45, '45'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_35, '35'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_25, '25'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_15, '15'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_5, '5'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_robot_move', + }, + paramsKeyMap: { + DIRECTION: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const direction = script.getNumberField('DIRECTION', script); + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const direction = script.getNumberField('DIRECTION', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [direction, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_motor_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_out_l, 1], + [Lang.Blocks.neo_lite_motor_out_r, 2], + [Lang.Blocks.neo_lite_motor_out_lr, 0], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_motor_stop', + }, + paramsKeyMap: { + DC: 0, + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const dc = script.getStringValue('DC', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_STOP, [dc]); + return script.callReturn(); + }, + }, + neo_lite_robot_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_lite_robot_stop', + }, + paramsKeyMap: { + // + }, + class: 'neo_lite_motor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP, []); + return script.callReturn(); + }, + }, + /** + * 서보모터 + */ + neo_lite_servo_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_servo_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_servo_title', + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_servo_reset: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_servo_reset', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_RESET, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_servo_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_servo_angle_360, '360'], + [Lang.Blocks.neo_lite_servo_angle_350, '350'], + [Lang.Blocks.neo_lite_servo_angle_340, '340'], + [Lang.Blocks.neo_lite_servo_angle_330, '330'], + [Lang.Blocks.neo_lite_servo_angle_320, '320'], + [Lang.Blocks.neo_lite_servo_angle_310, '310'], + [Lang.Blocks.neo_lite_servo_angle_300, '300'], + [Lang.Blocks.neo_lite_servo_angle_290, '290'], + [Lang.Blocks.neo_lite_servo_angle_280, '280'], + [Lang.Blocks.neo_lite_servo_angle_270, '270'], + [Lang.Blocks.neo_lite_servo_angle_260, '260'], + [Lang.Blocks.neo_lite_servo_angle_250, '250'], + [Lang.Blocks.neo_lite_servo_angle_240, '240'], + [Lang.Blocks.neo_lite_servo_angle_230, '230'], + [Lang.Blocks.neo_lite_servo_angle_220, '220'], + [Lang.Blocks.neo_lite_servo_angle_210, '210'], + [Lang.Blocks.neo_lite_servo_angle_200, '200'], + [Lang.Blocks.neo_lite_servo_angle_190, '190'], + [Lang.Blocks.neo_lite_servo_angle_180, '180'], + [Lang.Blocks.neo_lite_servo_angle_170, '170'], + [Lang.Blocks.neo_lite_servo_angle_160, '160'], + [Lang.Blocks.neo_lite_servo_angle_150, '150'], + [Lang.Blocks.neo_lite_servo_angle_140, '140'], + [Lang.Blocks.neo_lite_servo_angle_130, '130'], + [Lang.Blocks.neo_lite_servo_angle_120, '120'], + [Lang.Blocks.neo_lite_servo_angle_110, '110'], + [Lang.Blocks.neo_lite_servo_angle_100, '100'], + [Lang.Blocks.neo_lite_servo_angle_90, '90'], + [Lang.Blocks.neo_lite_servo_angle_80, '80'], + [Lang.Blocks.neo_lite_servo_angle_70, '70'], + [Lang.Blocks.neo_lite_servo_angle_60, '60'], + [Lang.Blocks.neo_lite_servo_angle_50, '50'], + [Lang.Blocks.neo_lite_servo_angle_40, '40'], + [Lang.Blocks.neo_lite_servo_angle_30, '30'], + [Lang.Blocks.neo_lite_servo_angle_20, '20'], + [Lang.Blocks.neo_lite_servo_angle_10, '10'], + [Lang.Blocks.neo_lite_servo_angle_0, '0'], + [Lang.Blocks.neo_lite_servo_angle_n10, '-10'], + [Lang.Blocks.neo_lite_servo_angle_n20, '-20'], + [Lang.Blocks.neo_lite_servo_angle_n30, '-30'], + [Lang.Blocks.neo_lite_servo_angle_n40, '-40'], + [Lang.Blocks.neo_lite_servo_angle_n50, '-50'], + [Lang.Blocks.neo_lite_servo_angle_n60, '-60'], + [Lang.Blocks.neo_lite_servo_angle_n70, '-70'], + [Lang.Blocks.neo_lite_servo_angle_n80, '-80'], + [Lang.Blocks.neo_lite_servo_angle_n90, '-90'], + [Lang.Blocks.neo_lite_servo_angle_n100, '-100'], + [Lang.Blocks.neo_lite_servo_angle_n110, '-110'], + [Lang.Blocks.neo_lite_servo_angle_n120, '-120'], + [Lang.Blocks.neo_lite_servo_angle_n130, '-130'], + [Lang.Blocks.neo_lite_servo_angle_n140, '-140'], + [Lang.Blocks.neo_lite_servo_angle_n150, '-150'], + [Lang.Blocks.neo_lite_servo_angle_n160, '-160'], + [Lang.Blocks.neo_lite_servo_angle_n170, '-170'], + [Lang.Blocks.neo_lite_servo_angle_n180, '-180'], + [Lang.Blocks.neo_lite_servo_angle_n190, '-190'], + [Lang.Blocks.neo_lite_servo_angle_n200, '-200'], + [Lang.Blocks.neo_lite_servo_angle_n210, '-210'], + [Lang.Blocks.neo_lite_servo_angle_n220, '-220'], + [Lang.Blocks.neo_lite_servo_angle_n230, '-230'], + [Lang.Blocks.neo_lite_servo_angle_n240, '-240'], + [Lang.Blocks.neo_lite_servo_angle_n250, '-250'], + [Lang.Blocks.neo_lite_servo_angle_n260, '-260'], + [Lang.Blocks.neo_lite_servo_angle_n270, '-270'], + [Lang.Blocks.neo_lite_servo_angle_n280, '-280'], + [Lang.Blocks.neo_lite_servo_angle_n290, '-290'], + [Lang.Blocks.neo_lite_servo_angle_n300, '-300'], + [Lang.Blocks.neo_lite_servo_angle_n310, '-310'], + [Lang.Blocks.neo_lite_servo_angle_n320, '-320'], + [Lang.Blocks.neo_lite_servo_angle_n330, '-330'], + [Lang.Blocks.neo_lite_servo_angle_n340, '-340'], + [Lang.Blocks.neo_lite_servo_angle_n350, '-350'], + [Lang.Blocks.neo_lite_servo_angle_n360, '-360'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_lite_servo_angle', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const angle = script.getStringField('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (angle === 'IN1' || angle === 'IN2' || angle === 'IN3') { + if (speed === 'IN1' || angle === 'IN2' || angle === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } else { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_servo_angle_var: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_lite_arg_servo_angle', + }, + null, + null, + ], + type: 'neo_lite_servo_angle_var', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringField('OUTPUT', script); + const angle = script.getNumberValue('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE, [output, angle, speed]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_servo_angle_wait: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_servo_angle_360, '360'], + [Lang.Blocks.neo_lite_servo_angle_350, '350'], + [Lang.Blocks.neo_lite_servo_angle_340, '340'], + [Lang.Blocks.neo_lite_servo_angle_330, '330'], + [Lang.Blocks.neo_lite_servo_angle_320, '320'], + [Lang.Blocks.neo_lite_servo_angle_310, '310'], + [Lang.Blocks.neo_lite_servo_angle_300, '300'], + [Lang.Blocks.neo_lite_servo_angle_290, '290'], + [Lang.Blocks.neo_lite_servo_angle_280, '280'], + [Lang.Blocks.neo_lite_servo_angle_270, '270'], + [Lang.Blocks.neo_lite_servo_angle_260, '260'], + [Lang.Blocks.neo_lite_servo_angle_250, '250'], + [Lang.Blocks.neo_lite_servo_angle_240, '240'], + [Lang.Blocks.neo_lite_servo_angle_230, '230'], + [Lang.Blocks.neo_lite_servo_angle_220, '220'], + [Lang.Blocks.neo_lite_servo_angle_210, '210'], + [Lang.Blocks.neo_lite_servo_angle_200, '200'], + [Lang.Blocks.neo_lite_servo_angle_190, '190'], + [Lang.Blocks.neo_lite_servo_angle_180, '180'], + [Lang.Blocks.neo_lite_servo_angle_170, '170'], + [Lang.Blocks.neo_lite_servo_angle_160, '160'], + [Lang.Blocks.neo_lite_servo_angle_150, '150'], + [Lang.Blocks.neo_lite_servo_angle_140, '140'], + [Lang.Blocks.neo_lite_servo_angle_130, '130'], + [Lang.Blocks.neo_lite_servo_angle_120, '120'], + [Lang.Blocks.neo_lite_servo_angle_110, '110'], + [Lang.Blocks.neo_lite_servo_angle_100, '100'], + [Lang.Blocks.neo_lite_servo_angle_90, '90'], + [Lang.Blocks.neo_lite_servo_angle_80, '80'], + [Lang.Blocks.neo_lite_servo_angle_70, '70'], + [Lang.Blocks.neo_lite_servo_angle_60, '60'], + [Lang.Blocks.neo_lite_servo_angle_50, '50'], + [Lang.Blocks.neo_lite_servo_angle_40, '40'], + [Lang.Blocks.neo_lite_servo_angle_30, '30'], + [Lang.Blocks.neo_lite_servo_angle_20, '20'], + [Lang.Blocks.neo_lite_servo_angle_10, '10'], + [Lang.Blocks.neo_lite_servo_angle_0, '0'], + [Lang.Blocks.neo_lite_servo_angle_n10, '-10'], + [Lang.Blocks.neo_lite_servo_angle_n20, '-20'], + [Lang.Blocks.neo_lite_servo_angle_n30, '-30'], + [Lang.Blocks.neo_lite_servo_angle_n40, '-40'], + [Lang.Blocks.neo_lite_servo_angle_n50, '-50'], + [Lang.Blocks.neo_lite_servo_angle_n60, '-60'], + [Lang.Blocks.neo_lite_servo_angle_n70, '-70'], + [Lang.Blocks.neo_lite_servo_angle_n80, '-80'], + [Lang.Blocks.neo_lite_servo_angle_n90, '-90'], + [Lang.Blocks.neo_lite_servo_angle_n100, '-100'], + [Lang.Blocks.neo_lite_servo_angle_n110, '-110'], + [Lang.Blocks.neo_lite_servo_angle_n120, '-120'], + [Lang.Blocks.neo_lite_servo_angle_n130, '-130'], + [Lang.Blocks.neo_lite_servo_angle_n140, '-140'], + [Lang.Blocks.neo_lite_servo_angle_n150, '-150'], + [Lang.Blocks.neo_lite_servo_angle_n160, '-160'], + [Lang.Blocks.neo_lite_servo_angle_n170, '-170'], + [Lang.Blocks.neo_lite_servo_angle_n180, '-180'], + [Lang.Blocks.neo_lite_servo_angle_n190, '-190'], + [Lang.Blocks.neo_lite_servo_angle_n200, '-200'], + [Lang.Blocks.neo_lite_servo_angle_n210, '-210'], + [Lang.Blocks.neo_lite_servo_angle_n220, '-220'], + [Lang.Blocks.neo_lite_servo_angle_n230, '-230'], + [Lang.Blocks.neo_lite_servo_angle_n240, '-240'], + [Lang.Blocks.neo_lite_servo_angle_n250, '-250'], + [Lang.Blocks.neo_lite_servo_angle_n260, '-260'], + [Lang.Blocks.neo_lite_servo_angle_n270, '-270'], + [Lang.Blocks.neo_lite_servo_angle_n280, '-280'], + [Lang.Blocks.neo_lite_servo_angle_n290, '-290'], + [Lang.Blocks.neo_lite_servo_angle_n300, '-300'], + [Lang.Blocks.neo_lite_servo_angle_n310, '-310'], + [Lang.Blocks.neo_lite_servo_angle_n320, '-320'], + [Lang.Blocks.neo_lite_servo_angle_n330, '-330'], + [Lang.Blocks.neo_lite_servo_angle_n340, '-340'], + [Lang.Blocks.neo_lite_servo_angle_n350, '-350'], + [Lang.Blocks.neo_lite_servo_angle_n360, '-360'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_lite_servo_angle_wait', + }, + paramsKeyMap: { + OUTPUT: 0, + ANGLE: 1, + SPEED: 2, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringField('OUTPUT', script); + const angle = script.getStringField('ANGLE', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (angle === 'IN1' || angle === 'IN2' || angle === 'IN3') { + if (speed === 'IN1' || angle === 'IN2' || angle === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [ + output, + angle, + speed, + ]); + } else { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [ + output, + angle, + speed, + ]); + } + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ANGLE_WAIT, [output, angle, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_servo_rotate: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_servo_direction_f, 1], + [Lang.Blocks.neo_lite_servo_direction_b, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_lite_servo_rotate', + }, + paramsKeyMap: { + OUTPUT: 0, + DIRECTION: 1, + SPEED: 2, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const direction = script.getStringField('DIRECTION', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.SERVO_ROTATE, [output, direction, speed]); + } else { + this.requestCommand(blockId, NeoBlockType.SERVO_ROTATE, [output, direction, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_servo_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_servo_stop', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_lite_servo', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SERVO_STOP, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 라인트레이서 + */ + neo_lite_line_tracer_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_line_tracer_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_line_tracer_title', + }, + class: 'neo_lite_line_tracer', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_line_tracer_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_line_tracer_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_lite_line_tracer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + const duration = script.getStringValue('DURATION', script); + if (speed === 'IN1' || speed === 'IN2' || speed === 'IN3') { + this.requestExtCommand(blockId, NeoBlockType.LINE_TRACER_START, [speed]); + } else { + this.requestCommand(blockId, NeoBlockType.LINE_TRACER_START, [speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_TRACER_START, [0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_line_cross_move: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_line_cross_move_1, 1], + [Lang.Blocks.neo_lite_line_cross_move_2, 2], + [Lang.Blocks.neo_lite_line_cross_move_3, 3], + [Lang.Blocks.neo_lite_line_cross_move_4, 4], + [Lang.Blocks.neo_lite_line_cross_move_5, 5], + [Lang.Blocks.neo_lite_line_cross_move_6, 6], + [Lang.Blocks.neo_lite_line_cross_move_7, 7], + [Lang.Blocks.neo_lite_line_cross_move_8, 8], + [Lang.Blocks.neo_lite_line_cross_move_9, 9], + [Lang.Blocks.neo_lite_line_cross_move_10, 10], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_line_cross_move', + }, + paramsKeyMap: { + COUNT: 0, + }, + class: 'neo_lite_line_tracer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const count = script.getStringValue('COUNT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_CROSS_MOVE, [count]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_line_cross_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_turn_direction_l, 10], + [Lang.Blocks.neo_lite_turn_direction_r, 11], + [Lang.Blocks.neo_lite_turn_direction_u, 12], + ], + value: 10, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_line_cross_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_lite_line_tracer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const direction = script.getStringValue('DIRECTION', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LINE_CROSS_TURN, [direction]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 자율주행 + */ + neo_lite_auto_driving_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_auto_driving_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_auto_driving_title', + }, + class: 'neo_lite_auto_driving', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_auto_driving_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_auto_driving_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_lite_auto_driving', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const speed = script.getStringField('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [speed]); + } else { + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [speed]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_START, [0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_auto_driving_sensor_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1_2, 0x10], + [Lang.Blocks.neo_lite_input_11_12, 0x11], + [Lang.Blocks.neo_lite_input_13_14, 0x12], + [Lang.Blocks.neo_lite_input_21_22, 0x13], + [Lang.Blocks.neo_lite_input_23_24, 0x14], + ], + value: 0x10, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_lite_auto_driving_sensor_start', + }, + paramsKeyMap: { + SENSOR: 0, + SPEED: 1, + }, + class: 'neo_lite_auto_driving', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const sensor = script.getNumberField('SENSOR', script); + const speed = script.getStringField('SPEED', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + if (speed.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.AUTO_DRIVING_SENSOR_START, [ + sensor, + speed, + ]); + } else { + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_SENSOR_START, [sensor, speed]); + } + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_auto_driving_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_lite_auto_driving_stop', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_lite_auto_driving', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.AUTO_DRIVING_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 자율주차 + */ + neo_lite_auto_parking_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_auto_parking_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_auto_parking_title', + }, + class: 'neo_lite_auto_parking', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_auto_parking_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_auto_parking_which_l, 1], + [Lang.Blocks.neo_lite_auto_parking_which_r, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_auto_parking_direction_b, 1], + [Lang.Blocks.neo_lite_auto_parking_direction_s, 2], + ], + value: 1, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_lite_auto_parking_start', + }, + paramsKeyMap: { + WHICH: 0, + DIRECTION: 1, + }, + class: 'neo_lite_auto_parking', + isNotFor: ['NeoLite'], + func: async (sprite, script) => { + const direction = script.getNumberValue('DIRECTION', script); + if (direction === 1) { + return this.runAutoParkingBackward(script); + } else { + return this.runAutoParkingSide(script); + } + }, + }, + /** + * 차선변경 + */ + neo_lite_line_change_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_line_change_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_line_change_title', + }, + class: 'neo_lite_line_change', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_line_change_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_line_change_direction_l, 2], + [Lang.Blocks.neo_lite_line_change_direction_r, 3], + ], + value: 2, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_line_change_start', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_lite_line_change', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + neo_lite_line_change_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_turn_direction_l, 4], + [Lang.Blocks.neo_lite_turn_direction_r, 5], + [Lang.Blocks.neo_lite_turn_direction_u, 6], + ], + value: 4, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_line_change_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_lite_line_change', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + /** + * 골목주행 + */ + neo_lite_auto_detect_wall_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_auto_detect_wall_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_auto_detect_wall_title', + }, + class: 'neo_lite_auto_detect_wall', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_auto_detect_wall_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_auto_detect_wall_start', + }, + paramsKeyMap: { + SPEED: 0, + DURATION: 1, + }, + class: 'neo_lite_auto_detect_wall', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + neo_lite_auto_detect_wall_turn: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_turn_direction_l, 2], + [Lang.Blocks.neo_lite_turn_direction_r, 3], + [Lang.Blocks.neo_lite_turn_direction_u, 4], + ], + value: 2, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_auto_detect_wall_turn', + }, + paramsKeyMap: { + DIRECTION: 0, + }, + class: 'neo_lite_auto_detect_wall', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + return script.callReturn(); + }, + }, + /** + * LED + */ + neo_lite_led_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_led_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_led_title', + }, + class: 'neo_lite_led', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_led_on: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_led_brightness_100, '100'], + [Lang.Blocks.neo_lite_led_brightness_90, '90'], + [Lang.Blocks.neo_lite_led_brightness_80, '80'], + [Lang.Blocks.neo_lite_led_brightness_70, '70'], + [Lang.Blocks.neo_lite_led_brightness_60, '60'], + [Lang.Blocks.neo_lite_led_brightness_50, '50'], + [Lang.Blocks.neo_lite_led_brightness_40, '40'], + [Lang.Blocks.neo_lite_led_brightness_30, '30'], + [Lang.Blocks.neo_lite_led_brightness_20, '20'], + [Lang.Blocks.neo_lite_led_brightness_10, '10'], + [Lang.Blocks.neo_lite_led_brightness_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_led_on', + }, + paramsKeyMap: { + OUTPUT: 0, + BRIGHTNESS: 1, + DURATION: 2, + }, + class: 'neo_lite_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const brightness = script.getStringValue('BRIGHTNESS', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (brightness.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.LED_ON, [output, brightness]); + } else { + this.requestCommand(blockId, NeoBlockType.LED_ON, [output, brightness]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.block_id = blockId; + script.exec_phase = ExecPhase.PENDING_STOP; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringField('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_ON, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_led_blink: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_led_blink_speed_1, 500], + [Lang.Blocks.neo_lite_led_blink_speed_2, 400], + [Lang.Blocks.neo_lite_led_blink_speed_3, 300], + [Lang.Blocks.neo_lite_led_blink_speed_4, 200], + [Lang.Blocks.neo_lite_led_blink_speed_5, 100], + ], + value: 500, + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_led_blink', + }, + paramsKeyMap: { + OUTPUT: 0, + SPEED: 1, + DURATION: 2, + }, + class: 'neo_lite_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const speed = script.getStringValue('SPEED', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.LED_BLINK, [output, speed, 100]); + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_BLINK, [output, 0, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_led_off: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_led_off', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_lite_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LED_OFF, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 컬러 LED + */ + neo_lite_color_led_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_color_led_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_color_led_title', + }, + class: 'neo_lite_color_led', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_color_led_on: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Color', + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_color_led_on', + }, + paramsKeyMap: { + OUTPUT: 0, + COLOR: 1, + DURATION: 2, + }, + class: 'neo_lite_color_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const color = script.getStringValue('COLOR', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.COLOR_LED_ON, [output, color]); + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.COLOR_LED_ON, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_color_led_off: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_color_led_off', + }, + paramsKeyMap: { + OUTPUT: 0, + }, + class: 'neo_lite_color_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.COLOR_LED_OFF, [output]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + neo_lite_color_led_on_with_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_lite_color_led_on_with_sensor', + }, + paramsKeyMap: { + INPUT: 0, + OUTPUT: 1, + }, + class: 'neo_lite_color_led', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const input = script.getStringValue('INPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestExtCommand(blockId, NeoBlockType.COLOR_LED_ON_SENSOR, [output, input]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 출력 + */ + neo_lite_set_output_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_set_output_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_set_output_title', + }, + class: 'neo_lite_set_output', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_set_output: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + [Lang.Blocks.neo_lite_output_12, 'OUT12'], + [Lang.Blocks.neo_lite_output_123, 'OUT123'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_set_output_value_255, '255'], + [Lang.Blocks.neo_lite_set_output_value_250, '250'], + [Lang.Blocks.neo_lite_set_output_value_245, '245'], + [Lang.Blocks.neo_lite_set_output_value_240, '240'], + [Lang.Blocks.neo_lite_set_output_value_235, '235'], + [Lang.Blocks.neo_lite_set_output_value_230, '230'], + [Lang.Blocks.neo_lite_set_output_value_225, '225'], + [Lang.Blocks.neo_lite_set_output_value_220, '220'], + [Lang.Blocks.neo_lite_set_output_value_215, '215'], + [Lang.Blocks.neo_lite_set_output_value_210, '210'], + [Lang.Blocks.neo_lite_set_output_value_205, '205'], + [Lang.Blocks.neo_lite_set_output_value_200, '200'], + [Lang.Blocks.neo_lite_set_output_value_195, '195'], + [Lang.Blocks.neo_lite_set_output_value_190, '190'], + [Lang.Blocks.neo_lite_set_output_value_185, '185'], + [Lang.Blocks.neo_lite_set_output_value_180, '180'], + [Lang.Blocks.neo_lite_set_output_value_175, '175'], + [Lang.Blocks.neo_lite_set_output_value_170, '170'], + [Lang.Blocks.neo_lite_set_output_value_165, '165'], + [Lang.Blocks.neo_lite_set_output_value_160, '160'], + [Lang.Blocks.neo_lite_set_output_value_155, '155'], + [Lang.Blocks.neo_lite_set_output_value_150, '150'], + [Lang.Blocks.neo_lite_set_output_value_145, '145'], + [Lang.Blocks.neo_lite_set_output_value_140, '140'], + [Lang.Blocks.neo_lite_set_output_value_135, '135'], + [Lang.Blocks.neo_lite_set_output_value_130, '130'], + [Lang.Blocks.neo_lite_set_output_value_125, '125'], + [Lang.Blocks.neo_lite_set_output_value_120, '120'], + [Lang.Blocks.neo_lite_set_output_value_115, '115'], + [Lang.Blocks.neo_lite_set_output_value_110, '110'], + [Lang.Blocks.neo_lite_set_output_value_105, '105'], + [Lang.Blocks.neo_lite_set_output_value_100, '100'], + [Lang.Blocks.neo_lite_set_output_value_95, '95'], + [Lang.Blocks.neo_lite_set_output_value_90, '90'], + [Lang.Blocks.neo_lite_set_output_value_85, '85'], + [Lang.Blocks.neo_lite_set_output_value_80, '80'], + [Lang.Blocks.neo_lite_set_output_value_75, '75'], + [Lang.Blocks.neo_lite_set_output_value_70, '70'], + [Lang.Blocks.neo_lite_set_output_value_65, '65'], + [Lang.Blocks.neo_lite_set_output_value_60, '60'], + [Lang.Blocks.neo_lite_set_output_value_55, '55'], + [Lang.Blocks.neo_lite_set_output_value_50, '50'], + [Lang.Blocks.neo_lite_set_output_value_45, '45'], + [Lang.Blocks.neo_lite_set_output_value_40, '40'], + [Lang.Blocks.neo_lite_set_output_value_35, '35'], + [Lang.Blocks.neo_lite_set_output_value_30, '30'], + [Lang.Blocks.neo_lite_set_output_value_25, '25'], + [Lang.Blocks.neo_lite_set_output_value_20, '20'], + [Lang.Blocks.neo_lite_set_output_value_15, '15'], + [Lang.Blocks.neo_lite_set_output_value_10, '10'], + [Lang.Blocks.neo_lite_set_output_value_5, '5'], + [Lang.Blocks.neo_lite_set_output_value_0, '0'], + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [ + null, + null, + { + type: 'neo_lite_arg_duration', + }, + null, + ], + type: 'neo_lite_set_output', + }, + paramsKeyMap: { + OUTPUT: 0, + VALUE: 1, + DURATION: 2, + }, + class: 'neo_lite_set_output', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const output = script.getStringValue('OUTPUT', script); + const value = script.getStringValue('VALUE', script); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + if (value.indexOf('IN') >= 0) { + this.requestExtCommand(blockId, NeoBlockType.SET_OUTPUT, [output, value]); + } else { + this.requestCommand(blockId, NeoBlockType.SET_OUTPUT, [output, value]); + } + if (duration === 'c' || !Entry.parseNumber(duration)) { + script.exec_phase = ExecPhase.PENDING_STOP; + script.block_id = blockId; + } else { + script.exec_phase = ExecPhase.SET_TIMEOUT; + } + } else if (script.exec_phase === ExecPhase.SET_TIMEOUT) { + const duration = script.getStringValue('DURATION', script); + const durationValue = Entry.parseNumber(duration); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, durationValue * 1000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const output = script.getStringValue('OUTPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.SET_OUTPUT, [output, 0]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * 센서 + */ + neo_lite_sensor_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_sensor_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_sensor_title', + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_sensor_in: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_lite_sensor_in', + }, + paramsKeyMap: { + INPUT: 0, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = this.sensorValues; + switch (input) { + case 'IN1': + return sensorData['in1Values'][0]; + case 'IN2': + return sensorData['in2Values'][0]; + case 'IN3': + return sensorData['in3Values'][0]; + } + return 0; + }, + }, + neo_lite_sensor_digital_in: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_sensor_in_digital_1, 0], + [Lang.Blocks.neo_lite_sensor_in_digital_2, 1], + [Lang.Blocks.neo_lite_sensor_in_digital_3, 2], + [Lang.Blocks.neo_lite_sensor_in_digital_4, 3], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_lite_sensor_digital_in', + }, + paramsKeyMap: { + INPUT: 0, + INDEX: 1, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const index = script.getNumberField('INDEX'); + const sensorData = this.sensorValues; + switch (input) { + case 'IN1': + return sensorData['in1Values'][index]; + case 'IN2': + return sensorData['in2Values'][index]; + case 'IN3': + return sensorData['in3Values'][index]; + } + return 0; + }, + }, + neo_lite_sensor_convert: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['IN1', 'IN1'], + ['IN2', 'IN2'], + ['IN3', 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [ + null, + { + type: 'number', + params: ['10'], + }, + { + type: 'number', + params: ['255'], + }, + { + type: 'number', + params: ['0'], + }, + { + type: 'number', + params: ['100'], + }, + ], + type: 'neo_lite_sensor_convert', + }, + paramsKeyMap: { + INPUT: 0, + FROM_MIN: 1, + FROM_MAX: 2, + TO_MIN: 3, + TO_MAX: 4, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = this.sensorValues; + let value = 0; + switch (input) { + case 'IN1': + value = sensorData['in1Values'][0]; + break; + case 'IN2': + value = sensorData['in2Values'][0]; + break; + case 'IN3': + value = sensorData['in3Values'][0]; + break; + } + let fromMin = script.getNumberValue('FROM_MIN', script); + let fromMax = script.getNumberValue('FROM_MAX', script); + let toMin = script.getNumberValue('TO_MIN', script); + let toMax = script.getNumberValue('TO_MAX', script); + + if (fromMin > fromMax) { + const temp = fromMin; + fromMin = fromMax; + fromMax = temp; + } + + if (toMin > toMax) { + const temp = toMin; + toMin = toMax; + toMax = temp; + } + + value -= fromMin; + value = value * ((toMax - toMin) / (fromMax - fromMin)); + value += toMin; + value = Math.min(toMax, value); + value = Math.max(toMin, value); + + return Math.round(value); + }, + }, + neo_lite_sensor_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + [Lang.Blocks.neo_lite_input_12, 'IN12'], + [Lang.Blocks.neo_lite_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_compare_gt, '>='], + [Lang.Blocks.neo_lite_compare_g, '>'], + [Lang.Blocks.neo_lite_compare_e, '='], + [Lang.Blocks.neo_lite_compare_l, '<'], + [Lang.Blocks.neo_lite_compare_lt, '<='], + ], + value: '>', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [null, null, 10], + type: 'neo_lite_sensor_compare', + }, + paramsKeyMap: { + INPUT: 0, + SYMBOL: 1, + VALUE: 2, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = this.sensorValues; + const symbol = script.getStringField('SYMBOL'); + const value = Entry.parseNumber(script.getStringValue('VALUE')); + + if (input === 'IN12') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + if (symbol === '=') { + return sensor1 === value && sensor2 === value; + } else if (symbol === '>') { + return sensor1 > value && sensor2 > value; + } else if (symbol === '<') { + return sensor1 < value && sensor2 < value; + } else if (symbol === '>=') { + return sensor1 >= value && sensor2 >= value; + } else if (symbol === '<=') { + return sensor1 <= value && sensor2 <= value; + } + } else if (input === 'IN123') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + const sensor3 = sensorData['in3Values'][0]; + if (symbol === '=') { + return sensor1 === value && sensor2 === value && sensor3 === value; + } else if (symbol === '>') { + return sensor1 > value && sensor2 > value && sensor3 > value; + } else if (symbol === '<') { + return sensor1 < value && sensor2 < value && sensor3 < value; + } else if (symbol === '>=') { + return sensor1 >= value && sensor2 >= value && sensor3 >= value; + } else if (symbol === '<=') { + return sensor1 <= value && sensor2 <= value && sensor3 <= value; + } + } else { + let sensorValue = 0; + switch (input) { + case 'IN1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'IN2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'IN3': + sensorValue = sensorData['in3Values'][0]; + break; + } + if (symbol === '=') { + return sensorValue === value; + } else if (symbol === '>') { + return sensorValue > value; + } else if (symbol === '<') { + return sensorValue < value; + } else if (symbol === '>=') { + return sensorValue >= value; + } else if (symbol === '<=') { + return sensorValue <= value; + } + } + return false; + }, + }, + neo_lite_sensor_between: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_compare_gt, '>='], + [Lang.Blocks.neo_lite_compare_g, '>'], + [Lang.Blocks.neo_lite_compare_e, '='], + [Lang.Blocks.neo_lite_compare_l, '<'], + [Lang.Blocks.neo_lite_compare_lt, '<='], + ], + value: '<', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + [Lang.Blocks.neo_lite_input_12, 'IN12'], + [Lang.Blocks.neo_lite_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_compare_gt, '>='], + [Lang.Blocks.neo_lite_compare_g, '>'], + [Lang.Blocks.neo_lite_compare_e, '='], + [Lang.Blocks.neo_lite_compare_l, '<'], + [Lang.Blocks.neo_lite_compare_lt, '<='], + ], + value: '<', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + ], + events: {}, + def: { + params: [10, null, null, null, 30], + type: 'neo_lite_sensor_between', + }, + paramsKeyMap: { + L_VALUE: 0, + L_SYMBOL: 1, + INPUT: 2, + R_SYMBOL: 3, + R_VALUE: 4, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = this.sensorValues; + const lSymbol = script.getStringField('L_SYMBOL'); + const lValue = Entry.parseNumber(script.getStringValue('L_VALUE')); + const rSymbol = script.getStringField('R_SYMBOL'); + const rValue = Entry.parseNumber(script.getStringValue('R_VALUE')); + + if (input === 'IN12') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensor1 && lValue === sensor2; + } else if (lSymbol === '>') { + lResult = lValue > sensor1 && lValue > sensor2; + } else if (lSymbol === '<') { + lResult = lValue < sensor1 && lValue < sensor2; + } else if (lSymbol === '>=') { + lResult = lValue >= sensor1 && lValue >= sensor2; + } else if (lSymbol === '<=') { + lResult = lValue <= sensor1 && lValue <= sensor2; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensor1 === rValue && sensor2 === rValue; + } else if (rSymbol === '>') { + rResult = sensor1 > rValue && sensor2 > rValue; + } else if (rSymbol === '<') { + rResult = sensor1 < rValue && sensor2 < rValue; + } else if (rSymbol === '>=') { + rResult = sensor1 >= rValue && sensor2 >= rValue; + } else if (rSymbol === '<=') { + rResult = sensor1 <= rValue && sensor2 <= rValue; + } + return lResult && rResult; + } else if (input === 'IN123') { + const sensor1 = sensorData['in1Values'][0]; + const sensor2 = sensorData['in2Values'][0]; + const sensor3 = sensorData['in3Values'][0]; + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensor1 && lValue === sensor2 && lValue === sensor3; + } else if (lSymbol === '>') { + lResult = lValue > sensor1 && lValue > sensor2 && lValue > sensor3; + } else if (lSymbol === '<') { + lResult = lValue < sensor1 && lValue < sensor2 && lValue < sensor3; + } else if (lSymbol === '>=') { + lResult = lValue >= sensor1 && lValue >= sensor2 && lValue >= sensor3; + } else if (lSymbol === '<=') { + lResult = lValue <= sensor1 && lValue <= sensor2 && lValue <= sensor3; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensor1 === rValue && sensor2 === rValue && sensor3 === rValue; + } else if (rSymbol === '>') { + rResult = sensor1 > rValue && sensor2 > rValue && sensor3 > rValue; + } else if (rSymbol === '<') { + rResult = sensor1 < rValue && sensor2 < rValue && sensor3 < rValue; + } else if (rSymbol === '>=') { + rResult = sensor1 >= rValue && sensor2 >= rValue && sensor3 >= rValue; + } else if (rSymbol === '<=') { + rResult = sensor1 <= rValue && sensor2 <= rValue && sensor3 <= rValue; + } + return lResult && rResult; + } else { + let sensorValue = 0; + switch (input) { + case 'IN1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'IN2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'IN3': + sensorValue = sensorData['in3Values'][0]; + break; + } + let lResult = false; + if (lSymbol === '=') { + lResult = lValue === sensorValue; + } else if (lSymbol === '>') { + lResult = lValue > sensorValue; + } else if (lSymbol === '<') { + lResult = lValue < sensorValue; + } else if (lSymbol === '>=') { + lResult = lValue >= sensorValue; + } else if (lSymbol === '<=') { + lResult = lValue <= sensorValue; + } + let rResult = false; + if (rSymbol === '=') { + rResult = sensorValue === rValue; + } else if (rSymbol === '>') { + rResult = sensorValue > rValue; + } else if (rSymbol === '<') { + rResult = sensorValue < rValue; + } else if (rSymbol === '>=') { + rResult = sensorValue >= rValue; + } else if (rSymbol === '<=') { + rResult = sensorValue <= rValue; + } + return lResult && rResult; + } + }, + }, + neo_lite_sensor_color_compare: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#ffffff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + [Lang.Blocks.neo_lite_input_12, 'IN12'], + [Lang.Blocks.neo_lite_input_123, 'IN123'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_color_black, 1], + [Lang.Blocks.neo_lite_color_white, 2], + [Lang.Blocks.neo_lite_color_red, 3], + [Lang.Blocks.neo_lite_color_yellow, 4], + [Lang.Blocks.neo_lite_color_green, 5], + [Lang.Blocks.neo_lite_color_blue, 6], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_sensor_color_compare', + }, + paramsKeyMap: { + INPUT: 0, + COLOR: 1, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const input = script.getStringField('INPUT'); + const sensorData = this.sensorValues; + const color = script.getNumberField('COLOR'); + let sensorValue = 0; + switch (input) { + case 'in1': + sensorValue = sensorData['in1Values'][0]; + break; + case 'in2': + sensorValue = sensorData['in2Values'][0]; + break; + case 'in3': + sensorValue = sensorData['in3Values'][0]; + break; + } + + if (color === 1) { + return sensorValue === 0; + } else if (color === 2) { + return sensorValue === 0; + } else if (color === 3) { + return sensorValue === 0; + } else if (color === 4) { + return sensorValue === 0; + } else if (color === 5) { + return sensorValue === 0; + } else if (color === 6) { + return sensorValue === 0; + } + return false; + }, + }, + neo_lite_sensor_button_pressed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#FFFFFF', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_button_1, '1'], + [Lang.Blocks.neo_lite_button_2, '2'], + [Lang.Blocks.neo_lite_button_3, '3'], + [Lang.Blocks.neo_lite_button_4, '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_button_on, 'ON'], + [Lang.Blocks.neo_lite_button_off, 'OFF'], + ], + value: 'on', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_sensor_button_pressed', + }, + paramsKeyMap: { + BUTTON: 0, + PRESSED: 1, + }, + class: 'neo_lite_sensor', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + const button = script.getNumberField('BUTTON'); + const pressed = script.getStringField('PRESSED'); + const sensorData = this.sensorValues; + const value = sensorData['IR']; + if (button === 1) { + if (pressed === 'ON') return value === 10; + else return value !== 10; + } else if (button === 2) { + if (pressed === 'ON') return value === 11; + else return value !== 11; + } else if (button === 3) { + if (pressed === 'ON') return value === 12; + else return value !== 12; + } else if (button === 4) { + if (pressed === 'ON') return value === 13; + else return value !== 13; + } + }, + }, + /** + * 버저 + */ + neo_lite_buzzer_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_buzzer_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_buzzer_title', + }, + class: 'neo_lite_buzzer', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_buzzer_start: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_buzzer_octave_1, '0'], + [Lang.Blocks.neo_lite_buzzer_octave_2, '1'], + [Lang.Blocks.neo_lite_buzzer_octave_3, '2'], + [Lang.Blocks.neo_lite_buzzer_octave_4, '3'], + [Lang.Blocks.neo_lite_buzzer_octave_5, '4'], + [Lang.Blocks.neo_lite_buzzer_octave_6, '5'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_buzzer_do, '1'], + [Lang.Blocks.neo_lite_buzzer_do_sharp, '2'], + [Lang.Blocks.neo_lite_buzzer_re, '3'], + [Lang.Blocks.neo_lite_buzzer_re_sharp, '4'], + [Lang.Blocks.neo_lite_buzzer_mi, '5'], + [Lang.Blocks.neo_lite_buzzer_fa, '6'], + [Lang.Blocks.neo_lite_buzzer_fa_sharp, '7'], + [Lang.Blocks.neo_lite_buzzer_sol, '8'], + [Lang.Blocks.neo_lite_buzzer_sol_sharp, '9'], + [Lang.Blocks.neo_lite_buzzer_la, '10'], + [Lang.Blocks.neo_lite_buzzer_la_sharp, '11'], + [Lang.Blocks.neo_lite_buzzer_ti, '12'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_buzzer_whole_note, '1'], + [Lang.Blocks.neo_lite_buzzer_half_note, '2'], + [Lang.Blocks.neo_lite_buzzer_quarter_note, '4'], + [Lang.Blocks.neo_lite_buzzer_8th_note, '8'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, null], + type: 'neo_lite_buzzer_start', + }, + paramsKeyMap: { + OCTAVE: 0, + NOTE: 1, + DURATION: 2, + }, + class: 'neo_lite_buzzer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + const octave = script.getNumberField('OCTAVE', script); + const note = script.getNumberField('NOTE', script); + const value = Math.min(note + 12 * octave, 72); + const duration = script.getStringValue('DURATION', script); + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.BUZZER_START, [value]); + script.exec_phase = ExecPhase.WAIT_TIMEOUT; + setTimeout(function() { + script.exec_phase = ExecPhase.STOP; + }, (1 / duration) * 2000); + } else if (script.exec_phase === ExecPhase.WAIT_TIMEOUT) { + return script; + } else if (script.exec_phase === ExecPhase.STOP) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.BUZZER_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_lite_buzzer_with_sensor: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_input_1, 'IN1'], + [Lang.Blocks.neo_lite_input_2, 'IN2'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: 'IN1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'neo_lite_buzzer_with_sensor', + }, + paramsKeyMap: { + INPUT: 0, + }, + class: 'neo_lite_buzzer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const input = script.getStringValue('INPUT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestExtCommand(blockId, NeoBlockType.BUZZER_WITH_SENSOR, [input]); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_lite_buzzer_stop: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'neo_lite_buzzer_stop', + }, + paramsKeyMap: {}, + class: 'neo_lite_buzzer', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_STOP; + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.BUZZER_STOP, []); + } else if (script.exec_phase === ExecPhase.PENDING_STOP) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * LCD + */ + neo_lite_lcd_title: { + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#191970', + skeleton: 'basic_text', + skeletonOptions: { + contentPos: { + x: 5, + }, + }, + params: [ + { + type: 'Text', + text: Lang.template.neo_lite_lcd_title, + color: '#191970', + align: 'left', + }, + ], + def: { + type: 'neo_lite_lcd_title', + }, + class: 'neo_lite_lcd', + isNotFor: ['NeoLite'], + events: {}, + }, + neo_lite_lcd_image: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_lcd_image_1, '1'], + [Lang.Blocks.neo_lite_lcd_image_2, '2'], + [Lang.Blocks.neo_lite_lcd_image_3, '3'], + [Lang.Blocks.neo_lite_lcd_image_4, '4'], + [Lang.Blocks.neo_lite_lcd_image_5, '5'], + [Lang.Blocks.neo_lite_lcd_image_6, '6'], + [Lang.Blocks.neo_lite_lcd_image_7, '7'], + [Lang.Blocks.neo_lite_lcd_image_8, '8'], + [Lang.Blocks.neo_lite_lcd_image_9, '9'], + [Lang.Blocks.neo_lite_lcd_image_10, '10'], + [Lang.Blocks.neo_lite_lcd_image_11, '11'], + [Lang.Blocks.neo_lite_lcd_image_12, '12'], + [Lang.Blocks.neo_lite_lcd_image_13, '13'], + [Lang.Blocks.neo_lite_lcd_image_14, '14'], + [Lang.Blocks.neo_lite_lcd_image_15, '15'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'neo_lite_lcd_image', + }, + paramsKeyMap: { + OUTPUT: 0, + IMAGE: 1, + }, + class: 'neo_lite_lcd', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const image = script.getStringValue('IMAGE', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LCD_IMAGE, [output, image]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + + neo_lite_lcd_text: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_output_1, 'OUT1'], + [Lang.Blocks.neo_lite_output_2, 'OUT2'], + [Lang.Blocks.neo_lite_output_3, 'OUT3'], + ], + value: 'OUT1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, 'NEO', null], + type: 'neo_lite_lcd_text', + }, + paramsKeyMap: { + OUTPUT: 0, + TEXT: 1, + }, + class: 'neo_lite_lcd', + isNotFor: ['NeoLite'], + func: (sprite, script) => { + if (!script.exec_phase) { + script.exec_phase = ExecPhase.PENDING_RESPONSE; + const output = script.getStringValue('OUTPUT', script); + const text = script.getStringValue('TEXT', script); + const blockId = this.generateBlockId(); + script.block_id = blockId; + this.requestCommand(blockId, NeoBlockType.LCD_TEXT, [output, text]); + } else if (script.exec_phase === ExecPhase.PENDING_RESPONSE) { + if (!this.pendingResponseList[script.block_id]) { + delete script.block_id; + delete script.exec_phase; + return script.callReturn(); + } + } + return script; + }, + }, + /** + * ARG Blocks + */ + neo_lite_arg_motor_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_motor_speed_n10, '-10'], + [Lang.Blocks.neo_lite_motor_speed_n20, '-20'], + [Lang.Blocks.neo_lite_motor_speed_n30, '-30'], + [Lang.Blocks.neo_lite_motor_speed_n40, '-40'], + [Lang.Blocks.neo_lite_motor_speed_n50, '-50'], + [Lang.Blocks.neo_lite_motor_speed_n60, '-60'], + [Lang.Blocks.neo_lite_motor_speed_n70, '-70'], + [Lang.Blocks.neo_lite_motor_speed_n80, '-80'], + [Lang.Blocks.neo_lite_motor_speed_n90, '-90'], + [Lang.Blocks.neo_lite_motor_speed_n100, '-100'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_duration: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_duration_c, 'c'], + [Lang.Blocks.neo_lite_duration_0, '0'], + [Lang.Blocks.neo_lite_duration_1, '1'], + [Lang.Blocks.neo_lite_duration_2, '2'], + [Lang.Blocks.neo_lite_duration_3, '3'], + [Lang.Blocks.neo_lite_duration_4, '4'], + [Lang.Blocks.neo_lite_duration_5, '5'], + [Lang.Blocks.neo_lite_duration_6, '6'], + [Lang.Blocks.neo_lite_duration_7, '7'], + [Lang.Blocks.neo_lite_duration_8, '8'], + [Lang.Blocks.neo_lite_duration_9, '9'], + ], + value: 'c', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_robot_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_servo_angle: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_servo_angle_360, '360'], + [Lang.Blocks.neo_lite_servo_angle_350, '350'], + [Lang.Blocks.neo_lite_servo_angle_340, '340'], + [Lang.Blocks.neo_lite_servo_angle_330, '330'], + [Lang.Blocks.neo_lite_servo_angle_320, '320'], + [Lang.Blocks.neo_lite_servo_angle_310, '310'], + [Lang.Blocks.neo_lite_servo_angle_300, '300'], + [Lang.Blocks.neo_lite_servo_angle_290, '290'], + [Lang.Blocks.neo_lite_servo_angle_280, '280'], + [Lang.Blocks.neo_lite_servo_angle_270, '270'], + [Lang.Blocks.neo_lite_servo_angle_260, '260'], + [Lang.Blocks.neo_lite_servo_angle_250, '250'], + [Lang.Blocks.neo_lite_servo_angle_240, '240'], + [Lang.Blocks.neo_lite_servo_angle_230, '230'], + [Lang.Blocks.neo_lite_servo_angle_220, '220'], + [Lang.Blocks.neo_lite_servo_angle_210, '210'], + [Lang.Blocks.neo_lite_servo_angle_200, '200'], + [Lang.Blocks.neo_lite_servo_angle_190, '190'], + [Lang.Blocks.neo_lite_servo_angle_180, '180'], + [Lang.Blocks.neo_lite_servo_angle_170, '170'], + [Lang.Blocks.neo_lite_servo_angle_160, '160'], + [Lang.Blocks.neo_lite_servo_angle_150, '150'], + [Lang.Blocks.neo_lite_servo_angle_140, '140'], + [Lang.Blocks.neo_lite_servo_angle_130, '130'], + [Lang.Blocks.neo_lite_servo_angle_120, '120'], + [Lang.Blocks.neo_lite_servo_angle_110, '110'], + [Lang.Blocks.neo_lite_servo_angle_100, '100'], + [Lang.Blocks.neo_lite_servo_angle_90, '90'], + [Lang.Blocks.neo_lite_servo_angle_80, '80'], + [Lang.Blocks.neo_lite_servo_angle_70, '70'], + [Lang.Blocks.neo_lite_servo_angle_60, '60'], + [Lang.Blocks.neo_lite_servo_angle_50, '50'], + [Lang.Blocks.neo_lite_servo_angle_40, '40'], + [Lang.Blocks.neo_lite_servo_angle_30, '30'], + [Lang.Blocks.neo_lite_servo_angle_20, '20'], + [Lang.Blocks.neo_lite_servo_angle_10, '10'], + [Lang.Blocks.neo_lite_servo_angle_0, '0'], + [Lang.Blocks.neo_lite_servo_angle_n10, '-10'], + [Lang.Blocks.neo_lite_servo_angle_n20, '-20'], + [Lang.Blocks.neo_lite_servo_angle_n30, '-30'], + [Lang.Blocks.neo_lite_servo_angle_n40, '-40'], + [Lang.Blocks.neo_lite_servo_angle_n50, '-50'], + [Lang.Blocks.neo_lite_servo_angle_n60, '-60'], + [Lang.Blocks.neo_lite_servo_angle_n70, '-70'], + [Lang.Blocks.neo_lite_servo_angle_n80, '-80'], + [Lang.Blocks.neo_lite_servo_angle_n90, '-90'], + [Lang.Blocks.neo_lite_servo_angle_n100, '-100'], + [Lang.Blocks.neo_lite_servo_angle_n110, '-110'], + [Lang.Blocks.neo_lite_servo_angle_n120, '-120'], + [Lang.Blocks.neo_lite_servo_angle_n130, '-130'], + [Lang.Blocks.neo_lite_servo_angle_n140, '-140'], + [Lang.Blocks.neo_lite_servo_angle_n150, '-150'], + [Lang.Blocks.neo_lite_servo_angle_n160, '-160'], + [Lang.Blocks.neo_lite_servo_angle_n170, '-170'], + [Lang.Blocks.neo_lite_servo_angle_n180, '-180'], + [Lang.Blocks.neo_lite_servo_angle_n190, '-190'], + [Lang.Blocks.neo_lite_servo_angle_n200, '-200'], + [Lang.Blocks.neo_lite_servo_angle_n210, '-210'], + [Lang.Blocks.neo_lite_servo_angle_n220, '-220'], + [Lang.Blocks.neo_lite_servo_angle_n230, '-230'], + [Lang.Blocks.neo_lite_servo_angle_n240, '-240'], + [Lang.Blocks.neo_lite_servo_angle_n250, '-250'], + [Lang.Blocks.neo_lite_servo_angle_n260, '-260'], + [Lang.Blocks.neo_lite_servo_angle_n270, '-270'], + [Lang.Blocks.neo_lite_servo_angle_n280, '-280'], + [Lang.Blocks.neo_lite_servo_angle_n290, '-290'], + [Lang.Blocks.neo_lite_servo_angle_n300, '-300'], + [Lang.Blocks.neo_lite_servo_angle_n310, '-310'], + [Lang.Blocks.neo_lite_servo_angle_n320, '-320'], + [Lang.Blocks.neo_lite_servo_angle_n330, '-330'], + [Lang.Blocks.neo_lite_servo_angle_n340, '-340'], + [Lang.Blocks.neo_lite_servo_angle_n350, '-350'], + [Lang.Blocks.neo_lite_servo_angle_n360, '-360'], + ], + value: '90', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_servo_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + ], + value: '50', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_auto_driving_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_motor_speed_100, '100'], + [Lang.Blocks.neo_lite_motor_speed_90, '90'], + [Lang.Blocks.neo_lite_motor_speed_80, '80'], + [Lang.Blocks.neo_lite_motor_speed_70, '70'], + [Lang.Blocks.neo_lite_motor_speed_60, '60'], + [Lang.Blocks.neo_lite_motor_speed_50, '50'], + [Lang.Blocks.neo_lite_motor_speed_40, '40'], + [Lang.Blocks.neo_lite_motor_speed_30, '30'], + [Lang.Blocks.neo_lite_motor_speed_20, '20'], + [Lang.Blocks.neo_lite_motor_speed_10, '10'], + [Lang.Blocks.neo_lite_motor_speed_0, '0'], + [Lang.Blocks.neo_lite_input_3, 'IN3'], + ], + value: '60', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_led_brightness: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_led_brightness_100, '100'], + [Lang.Blocks.neo_lite_led_brightness_90, '90'], + [Lang.Blocks.neo_lite_led_brightness_80, '80'], + [Lang.Blocks.neo_lite_led_brightness_70, '70'], + [Lang.Blocks.neo_lite_led_brightness_60, '60'], + [Lang.Blocks.neo_lite_led_brightness_50, '50'], + [Lang.Blocks.neo_lite_led_brightness_40, '40'], + [Lang.Blocks.neo_lite_led_brightness_30, '30'], + [Lang.Blocks.neo_lite_led_brightness_20, '20'], + [Lang.Blocks.neo_lite_led_brightness_10, '10'], + [Lang.Blocks.neo_lite_led_brightness_0, '0'], + ], + value: '100', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_led_blink_speed: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_led_blink_speed_1, '1'], + [Lang.Blocks.neo_lite_led_blink_speed_2, '2'], + [Lang.Blocks.neo_lite_led_blink_speed_3, '3'], + [Lang.Blocks.neo_lite_led_blink_speed_4, '4'], + [Lang.Blocks.neo_lite_led_blink_speed_5, '5'], + ], + value: '5', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + neo_lite_arg_set_output_value: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + [Lang.Blocks.neo_lite_set_output_value_255, '255'], + [Lang.Blocks.neo_lite_set_output_value_250, '250'], + [Lang.Blocks.neo_lite_set_output_value_245, '245'], + [Lang.Blocks.neo_lite_set_output_value_240, '240'], + [Lang.Blocks.neo_lite_set_output_value_235, '235'], + [Lang.Blocks.neo_lite_set_output_value_230, '230'], + [Lang.Blocks.neo_lite_set_output_value_225, '225'], + [Lang.Blocks.neo_lite_set_output_value_220, '220'], + [Lang.Blocks.neo_lite_set_output_value_215, '215'], + [Lang.Blocks.neo_lite_set_output_value_210, '210'], + [Lang.Blocks.neo_lite_set_output_value_205, '205'], + [Lang.Blocks.neo_lite_set_output_value_200, '200'], + [Lang.Blocks.neo_lite_set_output_value_195, '195'], + [Lang.Blocks.neo_lite_set_output_value_190, '190'], + [Lang.Blocks.neo_lite_set_output_value_185, '185'], + [Lang.Blocks.neo_lite_set_output_value_180, '180'], + [Lang.Blocks.neo_lite_set_output_value_175, '175'], + [Lang.Blocks.neo_lite_set_output_value_170, '170'], + [Lang.Blocks.neo_lite_set_output_value_165, '165'], + [Lang.Blocks.neo_lite_set_output_value_160, '160'], + [Lang.Blocks.neo_lite_set_output_value_155, '155'], + [Lang.Blocks.neo_lite_set_output_value_150, '150'], + [Lang.Blocks.neo_lite_set_output_value_145, '145'], + [Lang.Blocks.neo_lite_set_output_value_140, '140'], + [Lang.Blocks.neo_lite_set_output_value_135, '135'], + [Lang.Blocks.neo_lite_set_output_value_130, '130'], + [Lang.Blocks.neo_lite_set_output_value_125, '125'], + [Lang.Blocks.neo_lite_set_output_value_120, '120'], + [Lang.Blocks.neo_lite_set_output_value_115, '115'], + [Lang.Blocks.neo_lite_set_output_value_110, '110'], + [Lang.Blocks.neo_lite_set_output_value_105, '105'], + [Lang.Blocks.neo_lite_set_output_value_100, '100'], + [Lang.Blocks.neo_lite_set_output_value_95, '95'], + [Lang.Blocks.neo_lite_set_output_value_90, '90'], + [Lang.Blocks.neo_lite_set_output_value_85, '85'], + [Lang.Blocks.neo_lite_set_output_value_80, '80'], + [Lang.Blocks.neo_lite_set_output_value_75, '75'], + [Lang.Blocks.neo_lite_set_output_value_70, '70'], + [Lang.Blocks.neo_lite_set_output_value_65, '65'], + [Lang.Blocks.neo_lite_set_output_value_60, '60'], + [Lang.Blocks.neo_lite_set_output_value_55, '55'], + [Lang.Blocks.neo_lite_set_output_value_50, '50'], + [Lang.Blocks.neo_lite_set_output_value_45, '45'], + [Lang.Blocks.neo_lite_set_output_value_40, '40'], + [Lang.Blocks.neo_lite_set_output_value_35, '35'], + [Lang.Blocks.neo_lite_set_output_value_30, '30'], + [Lang.Blocks.neo_lite_set_output_value_25, '25'], + [Lang.Blocks.neo_lite_set_output_value_20, '20'], + [Lang.Blocks.neo_lite_set_output_value_15, '15'], + [Lang.Blocks.neo_lite_set_output_value_10, '10'], + [Lang.Blocks.neo_lite_set_output_value_5, '5'], + [Lang.Blocks.neo_lite_set_output_value_0, '0'], + ], + value: '255', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + }, + paramsKeyMap: { + VALUE: 0, + }, + class: 'neo_lite_arg', + isNotFor: ['NeoLite'], + func: function(sprite, script) { + return script.getStringField('VALUE'); + }, + }, + }; + } + + /* + Functions for logging + */ + logD(msg) { + if (this.isDebug) { + console.log(msg); + } + } + + logPdu(msg) { + if (this.isDebugPdu) { + this.logD(msg); + } + } + + logSensor(msg) { + if (this.isDebugSensor) { + this.logD(msg); + } + } + + byteArrayToHex(data) { + let hexStr = ''; + for (let i = 0; i < data.length; i++) { + hexStr += this.byteToHexString(data[i]); + hexStr += ' '; + } + return hexStr; + } + + byteToHexString(byte) { + return `0${byte.toString(16)}`.slice(-2).toUpperCase(); + } + + getCurrentTime() { + const date = new Date(); + return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()} ${date.getMilliseconds()}`; + } + + makeCommand(blockId, type, params) { + //const body = [FrameCode.BASIC, PduCode.ACTION_COMMAND, PduType.REQUEST]; + const body = [FrameCode.BASIC, PduCode.BASIC, blockId]; + if (type === NeoBlockType.MOTOR_MOVE) { + const which = params[0]; + const speed = Math.abs(params[1]); + const direction = params[1] < 0 ? 1 : 0; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(which, 2); + data.writeInt16LE(direction, 4); + body.push(...data); + } else if (type === NeoBlockType.MOTOR_MOVE_BOTH) { + const speedL = params[0]; + const speedR = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR_BOTH); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speedL, 0); + data.writeInt16LE(speedR, 2); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_MOVE) { + const robotCommand = params[0]; + const speed = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(robotCommand, 2); + body.push(...data); + } else if (type === NeoBlockType.MOTOR_STOP || type === NeoBlockType.AUTO_DRIVING_STOP) { + const which = params[0]; + const direction = 1; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + data.writeInt16LE(which, 2); + data.writeInt16LE(direction, 4); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_STOP) { + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SERVO_RESET) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.RESET); + const data = Buffer.from([0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE) { + const output = params[0]; + const angle = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ANGLE); + const data = Buffer.from([0, 0, 0, 0, 1, 0]); + data.writeInt16LE(angle, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE_WAIT) { + const output = params[0]; + const angle = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ANGLE_WAIT); + const data = Buffer.from([0, 0, 0, 0, 1, 0]); + data.writeInt16LE(angle, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ROTATE) { + const output = params[0]; + const direction = params[1]; + const speed = params[2]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.ROTATE); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_STOP) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.SERVO, ServoCommand.STOP); + } else if ( + type === NeoBlockType.LINE_TRACER_START || + type === NeoBlockType.AUTO_DRIVING_START || + type === NeoBlockType.AUTO_DETECT_WALL_START + ) { + const speed = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0x10, 0]); + data.writeInt16LE(speed, 0); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DRIVING_SENSOR_START) { + const sensor = params[0]; + const speed = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(speed, 0); + data.writeInt16LE(sensor, 2); + body.push(...data); + } else if (type === NeoBlockType.LINE_CROSS_MOVE) { + const count = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.LINE_TRACER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(count, 0); + body.push(...data); + } else if (type === NeoBlockType.LINE_CROSS_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.LINE_TRACER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(direction, 0); + body.push(...data); + } else if (type === NeoBlockType.AUTO_PARKING_START) { + // TODO : which 누락 + const which = params[0]; + const direction = params[1]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_PARKING); + const data = Buffer.from([0, 0]); + data.writeInt16LE(direction, 0); + body.push(...data); + } else if (type === NeoBlockType.LINE_CHANGE_START) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DRIVING); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.LINE_CHANGE_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DRIVING); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DETECT_WALL_TURN) { + const direction = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.AUTO_DETECT_WALL); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(60, 0); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_ON) { + const output = params[0]; + const brightness = params[1]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(brightness, 0); + body.push(...data); + } else if (type === NeoBlockType.LED_BLINK) { + const output = params[0]; + const speed = params[1]; + const brightness = params[2]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(brightness, 0); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_OFF) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_ON) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.COLOR_LED, LedCommand.ON); + const data = Buffer.from([0, 0, 0, 0, 0, 0]); + const color = params[1]; + if (color.length === 7 && color[0] === '#') { + const r = color.substr(1, 2); + const g = color.substr(3, 2); + const b = color.substr(5, 2); + data.writeInt16LE(parseInt(r, 16), 0); + data.writeInt16LE(parseInt(g, 16), 2); + data.writeInt16LE(parseInt(b, 16), 4); + } + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_OFF) { + const output = params[0]; + body.push(this.getUnitId(output), ActorKind.COLOR_LED, LedCommand.OFF); + } else if (type === NeoBlockType.SET_OUTPUT) { + const output = params[0]; + const value = params[1]; + body.push(this.getUnitId(output), ActorKind.LED, 0); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(value, 0); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_START) { + const value = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(value, 0); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_STOP) { + const value = params[0]; + body.push(UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + body.push(...data); + } else if (type === NeoBlockType.LCD_IMAGE) { + const output = this.getUnitId(params[0]); + const value = params[1]; + body.push(output, ActorKind.LCD, LcdCommand.IMAGE); + const data = Buffer.from([value, 0]); + body.push(...data); + } else if (type === NeoBlockType.LCD_TEXT) { + const output = this.getUnitId(params[0]); + const value = params[1]; + body.push(output, ActorKind.LCD, LcdCommand.TEXT); + body.push(0); // 글씨크기 : 지금 안됨. + if (value.length > 0) { + for (let idx = 0; idx < value.length; idx++) { + body.push(value.charCodeAt(idx)); + } + } + } + return body; + } + + makeCommandExt(blockId, type, params) { + const body = [FrameCode.BASIC]; + if (type === NeoBlockType.MOTOR_MOVE) { + const which = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.MOTOR); + const data = Buffer.from([unitId, 0, which, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.ROBOT_MOVE) { + const robotCommand = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([unitId, 0, 0, 0]); + data.writeInt16LE(robotCommand, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ANGLE || type === NeoBlockType.SERVO_ANGLE_WAIT) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + const speed = params[2]; + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.SERVO, ServoCommand.ANGLE); + const data = Buffer.from([inUnitId, 0, 0, 0, 1, 0]); + data.writeInt16LE(speed, 2); + body.push(...data); + } else if (type === NeoBlockType.SERVO_ROTATE) { + const unitId = this.getUnitId(params[0]); + const direction = params[1]; + const inUnitId = this.getUnitId(params[2]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.SERVO, ServoCommand.ROTATE); + const data = Buffer.from([inUnitId, 0, 0, 0]); + data.writeInt16LE(direction, 2); + body.push(...data); + } else if ( + type === NeoBlockType.LINE_TRACER_START || + type === NeoBlockType.AUTO_DRIVING_START || + type === NeoBlockType.AUTO_DETECT_WALL_START + ) { + const unitId = this.getUnitId(params[0]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([unitId, 0, 0x10, 0]); + body.push(...data); + } else if (type === NeoBlockType.AUTO_DRIVING_SENSOR_START) { + const sensor = params[0]; + const unitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.ROBOT); + const data = Buffer.from([0, 0, 0, 0]); + data.writeInt16LE(unitId, 0); + data.writeInt16LE(sensor, 2); + body.push(...data); + } else if (type === NeoBlockType.LED_ON) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.LED, 0); + const data = Buffer.from([inUnitId, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.SET_OUTPUT) { + const unitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_1, blockId, unitId, ActorKind.LED, 0); + const data = Buffer.from([inUnitId, 0, 0, 0]); + body.push(...data); + } else if (type === NeoBlockType.BUZZER_WITH_SENSOR) { + const sensorUnitId = this.getUnitId(params[0]); + body.push(PduCode.EXTEND_1, blockId, UnitId.CONTROLLER, ActorKind.CONTROLLER, ControllerCommand.BUZZER); + const data = Buffer.from([0, 0]); + data.writeInt16LE(sensorUnitId, 0); + body.push(...data); + } else if (type === NeoBlockType.COLOR_LED_ON_SENSOR) { + const outUnitId = this.getUnitId(params[0]); + const inUnitId = this.getUnitId(params[1]); + body.push(PduCode.EXTEND_3, blockId, outUnitId, ActorKind.COLOR_LED, LedCommand.ON); + const data = Buffer.from([inUnitId, 1, inUnitId, 2, inUnitId, 3]); + body.push(...data); + } + return body; + } + + /* + 후면주차 실행 (pending response 하지 않고 바로 다음 단계로 넘어감 : phase 가 너무 많아서 간소화) + 주석은 왼쪽 기준으로 오른쪽에서는 좌우만 바꿔준다. + */ + runAutoParkingBackward(script) { + const which = script.getNumberValue('WHICH', script); + const sensorData = this.sensorValues; + if (!script.exec_phase) { + // 1. 로봇 제자리 오른쪽 20% + script.exec_phase = '2_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 6 : 5, 20]); + setTimeout(() => { + script.exec_phase = '3_robot_stop'; + }, 3500); + } else if (script.exec_phase === '2_wait') { + // 2. 3.5초 기다리기 + } else if (script.exec_phase === '3_robot_stop') { + // 3. 로봇 정지 + script.exec_phase = '4_robot_rotate'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } else if (script.exec_phase === '4_robot_rotate') { + // 4. 로봇 제자리 왼쪽 20% + script.exec_phase = '5_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 5 : 6, 20]); + } else if (script.exec_phase === '5_wait_sensor') { + // 5. IN2 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in2Values[0] : sensorData.in1Values[0]; + if (compareValue > 40) { + script.exec_phase = '6_stop_robot'; + } + } else if (script.exec_phase === '6_stop_robot') { + // 6. 로봇 멈추기 + script.exec_phase = '7_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '8_robot_back'; + }, 1000); + } else if (script.exec_phase === '7_wait') { + // 7. 1초 기다리기 + } else if (script.exec_phase === '8_robot_back') { + // 8. 로봇 후진 20% + script.exec_phase = '9_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + } else if (script.exec_phase === '9_wait_sensor') { + // 9. IN1 20초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 20) { + script.exec_phase = '10_stop_robot'; + } + } else if (script.exec_phase === '10_stop_robot') { + // 10. 로봇 멈추기 + script.exec_phase = '11_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '12_adjustment'; + }, 1000); + } else if (script.exec_phase === '11_wait') { + // 11. 1초 기다리기 + } else if (script.exec_phase === '12_adjustment') { + // 12. IN2 가 IN1 보다 크면 [-20, 0] 아니면 [0, -20] , IN2 가 60보다 크면 break : 차체 조정시에는 좌우 구분 없음 + if (sensorData.in2Values[0] > sensorData.in1Values[0]) { + if (script.adjust_direction !== 'left') { + script.adjust_direction = 'left'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [-20, 0]); + } + } else { + if (script.adjust_direction !== 'right') { + script.adjust_direction = 'right'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.MOTOR_MOVE_BOTH, [0, -20]); + } + } + if (sensorData.in2Values[0] >= 60) { + script.exec_phase = '13_stop_robot'; + } + } else if (script.exec_phase === '13_stop_robot') { + // 13. 로봇 멈추기 + script.exec_phase = '14_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '15_robot_back'; + }, 1000); + } else if (script.exec_phase === '14_wait') { + // 14. 1초 기다리기 + } else if (script.exec_phase === '15_robot_back') { + // 15. 로봇 후진 20% + script.exec_phase = '16_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + setTimeout(() => { + script.exec_phase = '17_stop_robot'; + }, 2000); + } else if (script.exec_phase === '16_wait') { + // 16. 2초 기다리기 + } else if (script.exec_phase === '17_stop_robot') { + // 17. 로봇 멈추기 + script.exec_phase = 'end'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } + // + else if (script.exec_phase === 'end') { + // 종료 + return script.callReturn(); + } + + return script; + } + + runAutoParkingSide(script) { + const which = script.getNumberValue('WHICH', script); + const sensorData = this.sensorValues; + if (!script.exec_phase) { + // 1. 로봇 오른쪽 30% + script.exec_phase = '2_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 4 : 3, 30]); + setTimeout(() => { + script.exec_phase = '3_robot_stop'; + }, 2500); + } else if (script.exec_phase === '2_wait') { + // 2. 2초 기다리기 + } else if (script.exec_phase === '3_robot_stop') { + // 3. 로봇 정지 + script.exec_phase = '4_robot_back'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } else if (script.exec_phase === '4_robot_back') { + // 4. 로봇 뒤로 30% + script.exec_phase = '5_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 30]); + } else if (script.exec_phase === '5_wait_sensor') { + // 5. IN1 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 40) { + script.exec_phase = '6_wait_sensor'; + } + } else if (script.exec_phase === '6_wait_sensor') { + // 6. IN2 40 초과 기다리기 + const compareValue = which === 1 ? sensorData.in2Values[0] : sensorData.in1Values[0]; + if (compareValue > 40) { + script.exec_phase = '7_robot_stop'; + } + } else if (script.exec_phase === '7_robot_stop') { + // 7. 로봇 멈추기 + script.exec_phase = '8_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '9_robot_rotate'; + }, 1000); + } else if (script.exec_phase === '8_wait') { + // 8. 1초 기다리기 + } else if (script.exec_phase === '9_robot_rotate') { + // 9. 로봇 제자리왼쪽 20% + script.exec_phase = '10_wait_sensor'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [which === 1 ? 5 : 6, 20]); + } else if (script.exec_phase === '10_wait_sensor') { + // 10. IN1 40초과 기다리기 + const compareValue = which === 1 ? sensorData.in1Values[0] : sensorData.in2Values[0]; + if (compareValue > 40) { + script.exec_phase = '11_stop_robot'; + } + } else if (script.exec_phase === '11_stop_robot') { + // 11. 로봇 멈추기 + script.exec_phase = '12_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '13_adjustment'; + }, 1000); + } else if (script.exec_phase === '12_wait') { + // 12. 1초 기다리기 + } else if (script.exec_phase === '13_adjustment') { + // 13. 라인트레이서 + script.exec_phase = '14_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [7, 20]); + setTimeout(() => { + script.exec_phase = '15_robot_stop'; + }, 1500); + } else if (script.exec_phase === '14_wait') { + // 14. 1.5초 기다리기 + } else if (script.exec_phase === '15_robot_stop') { + // 15. 로봇 멈추기 + script.exec_phase = '16_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + setTimeout(() => { + script.exec_phase = '17_robot_back'; + }, 1000); + } else if (script.exec_phase === '16_wait') { + // 16. 1초 기다리기 + } else if (script.exec_phase === '17_robot_back') { + // 17. 로봇 후진 20% + script.exec_phase = '18_wait'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_MOVE, [2, 20]); + setTimeout(() => { + script.exec_phase = '19_stop_robot'; + }, 1000); + } else if (script.exec_phase === '18_wait') { + // 18. 1초 기다리기 + } else if (script.exec_phase === '19_stop_robot') { + // 19. 로봇 멈추기 + script.exec_phase = 'end'; + const blockId = this.generateBlockId(); + this.requestCommand(blockId, NeoBlockType.ROBOT_STOP); + } + // + else if (script.exec_phase === 'end') { + // 종료 + return script.callReturn(); + } + + return script; + } + })(); +})(); + +module.exports = Entry.NeoLite; diff --git a/src/playground/blocks/hardwareLite/metadata_choco_lite.json b/src/playground/blocks/hardwareLite/metadata_choco_lite.json new file mode 100644 index 0000000000..fe1f0763d4 --- /dev/null +++ b/src/playground/blocks/hardwareLite/metadata_choco_lite.json @@ -0,0 +1,9 @@ +{ + "name": "ChocoLite", + "version": "1.0.0", + "type": "hardware", + "title": "쪼코", + "description": "쪼코", + "imageName": "choco", + "moduleId": "450101" +} diff --git a/src/playground/blocks/hardwareLite/metadata_neo_lite.json b/src/playground/blocks/hardwareLite/metadata_neo_lite.json new file mode 100644 index 0000000000..0fa6bf9e99 --- /dev/null +++ b/src/playground/blocks/hardwareLite/metadata_neo_lite.json @@ -0,0 +1,9 @@ +{ + "name": "NeoLite", + "version": "1.0.0", + "type": "hardware", + "title": "네오(NEO)", + "description": "네오(NEO)", + "imageName": "neo", + "moduleId": "050801" +}