diff --git a/web-ui/code.js b/web-ui/code.js index c592287..b089823 100644 --- a/web-ui/code.js +++ b/web-ui/code.js @@ -1584,49 +1584,53 @@ function _boardSpecificHints(code = '') { const fqbn = _csbSelBoard.fqbn || ''; const arch = fqbn.split(':')[1] || ''; const usesWifi = /WiFi|ESP8266WiFi|HTTPClient|WebServer/i.test(code); - if (arch === 'esp32') { - const lines = [ - 'ESP32 코딩 규칙 (반드시 준수):', - '- analogWrite() 없음 → ledcAttach(pin, freq, res) + ledcWrite(pin, duty) 사용', - '- loop()에서 오래 blocking하면 watchdog(TG1WDT) 리셋 발생 → delay() 또는 yield() 필수', - '- SPIFFS 대신 LittleFS 권장 (esp32 3.x 코어)', - ]; - if (usesWifi) lines.splice(1, 0, - '- WiFi는 SoC 내장 — #include 절대 추가하지 말 것', - '- #include 하나로 충분 (esp32 코어 제공)', - '- WiFi.firmwareVersion() 없음 (WiFiNINA 전용)'); - return '\n' + lines.join('\n'); - } - if (arch === 'esp8266') { - const lines = [ - 'ESP8266 코딩 규칙 (반드시 준수):', - '- analogWrite() 있음 (PWM, 0-1023)', - '- loop()에서 yield() 또는 delay() 호출 필수 (watchdog 방지)', - '- SPI.h / ESP32Servo.h / ledcAttach 등 ESP32 전용 API 사용 금지', - ]; - if (usesWifi) lines.splice(1, 0, - '- WiFi: #include — #include 절대 사용 금지', - '- WiFi 암호화 상수: ENC_TYPE_NONE / ENC_TYPE_CCMP / ENC_TYPE_TKIP 사용 (WIFI_AUTH_OPEN 등 ESP32 상수 금지)', - '- WiFi 스캔: WiFi.scanNetworks() / WiFi.getNetworkInfo() / WiFi.getScanInfoByIndex() / bss_info 사용'); - return '\n' + lines.join('\n'); - } - if (arch === 'avr') { - const lines = ['AVR(Arduino) 코딩 규칙:']; - if (usesWifi) lines.push('- WiFi 실드: #include + #include 또는 #include '); - return '\n' + lines.join('\n'); - } - if (arch === 'stm32') { + + // 언어 직접 선택 (하드웨어 보드 아님) + if (fqbn === 'lang:python') { return '\n' + [ - 'STM32 (Arduino) 코딩 규칙 (반드시 준수):', - '- 언어: C++ (Arduino 스케치), Python 절대 사용 금지', - '- 핀 이름: PB_3·PA_0 등 STM32 PinName 상수 사용. Arduino D-number와 혼용 주의', - '- Serial = USART1 (PA9/PA10), Serial.begin(115200) 필수', - '- analogWrite() 없음 → HardwareTimer + PWM 채널 사용', - '- Wire(I2C1): SDA=PB7, SCL=PB6 (블루필 기본)', - '- SPI1: MOSI=PA7, MISO=PA6, SCK=PA5', + '언어: Python', + '- 순수 Python 코드로 작성하세요. Arduino/C++ 문법 사용 금지', + '- 스크립트는 표준 Python 환경에서 실행됩니다', ].join('\n'); } - return ''; + if (fqbn === 'lang:cpp') { + return '\n' + [ + '언어: C++ (일반)', + '- 표준 C++17 코드로 작성하세요. Arduino 전용 API 사용 금지', + ].join('\n'); + } + if (fqbn === 'lang:other') return ''; + + // 하드웨어 보드: 공통 Arduino 규칙 + arch별 추가 규칙 + if (!arch) return ''; + const base = ['Arduino (C++) 코딩 규칙:', '- 언어: C++ (Arduino 스케치). PC 전용 앱이 필요하면 해당 언어 병행 가능']; + const extra = []; + + if (arch === 'esp32') { + extra.push('- analogWrite() 없음 → ledcAttach(pin, freq, res) + ledcWrite(pin, duty)'); + extra.push('- loop() 장시간 blocking → watchdog 리셋. delay() 또는 yield() 필수'); + extra.push('- SPIFFS 대신 LittleFS 권장 (esp32 3.x 코어)'); + if (usesWifi) extra.push( + '- WiFi 내장 — #include 하나로 충분. SPI.h 추가 금지', + '- WiFi.firmwareVersion() 없음 (WiFiNINA 전용)'); + } else if (arch === 'esp8266') { + extra.push('- analogWrite() 있음 (PWM, 0-1023)'); + extra.push('- loop()에서 yield() 또는 delay() 필수 (watchdog 방지)'); + extra.push('- ledcAttach 등 ESP32 전용 API 사용 금지'); + if (usesWifi) extra.push( + '- WiFi: #include . #include 사용 금지', + '- 암호화 상수: ENC_TYPE_NONE / ENC_TYPE_CCMP / ENC_TYPE_TKIP'); + } else if (arch === 'stm32') { + extra.push('- 핀 이름: PB_3·PA_0 등 STM32 PinName 상수 사용'); + extra.push('- Serial = USART1 (PA9/PA10), Serial.begin(115200) 필수'); + extra.push('- analogWrite() 없음 → HardwareTimer + PWM 채널 사용'); + extra.push('- Wire(I2C1): SDA=PB7, SCL=PB6 / SPI1: MOSI=PA7, MISO=PA6, SCK=PA5'); + } else if (arch === 'avr') { + if (usesWifi) extra.push('- WiFi 실드: #include + #include '); + } + // sam, samd, megaavr 등은 base만 적용 + + return '\n' + [...base, ...extra].join('\n'); } async function csbCompileOnly() { @@ -2875,8 +2879,9 @@ function _buildCodeSystemPrompt() { const summaryBlock = _historySummary ? `\n[이전 대화 요약]\n${_historySummary}\n` : ''; const _activeCode = (() => { try { const f = codeFiles.find(f => f.id === activeCodeFileId); return f?.model?.getValue() || f?.content || ''; } catch { return ''; } })(); const boardHints = _boardSpecificHints(_activeCode); + const isLangOnly = _csbSelBoard?.fqbn?.startsWith('lang:'); const boardBlock = _csbSelBoard?.fqbn - ? `\n## 대상 보드: ${_csbSelBoard.name} (${_csbSelBoard.fqbn})${boardHints}\n` + ? `\n## ${isLangOnly ? '코딩 언어' : '대상 보드'}: ${_csbSelBoard.name}${isLangOnly ? '' : ` (${_csbSelBoard.fqbn})`}${boardHints}\n` : ''; // 에디터 파일 컨텍스트 — 로컬 폴더와 분리하여 강조 @@ -4840,16 +4845,37 @@ function csbBoardSelClose() { if (dd) dd.style.display = 'none'; } +const _LANG_BOARDS = [ + { fqbn: 'lang:python', name: '🐍 Python', desc: 'Python 스크립트' }, + { fqbn: 'lang:cpp', name: '⚡ C++ (일반)', desc: '표준 C++, Arduino 아님' }, + { fqbn: 'lang:other', name: '📝 기타 언어', desc: 'AI가 언어를 판단' }, +]; + async function csbBoardSelSearch() { const q = (document.getElementById('csb-board-sel-q')?.value || '').trim(); const list = document.getElementById('csb-board-sel-list'); if (!list) return; list.innerHTML = '
불러오는 중...
'; try { + // 언어 옵션 고정 섹션 + const langFiltered = q ? _LANG_BOARDS.filter(b => b.name.includes(q) || b.desc.includes(q)) : _LANG_BOARDS; + const langHtml = langFiltered.length ? [ + `
언어
`, + ...langFiltered.map(b => { + const sel = b.fqbn === _csbSelBoard.fqbn; + return `
+ ${_csbEsc(b.name)} + ${b.desc} +
`; + }), + `
보드
`, + ].join('') : ''; + const data = await api('/api/arduino/boards/listall?q=' + encodeURIComponent(q)); const boards = data.boards || []; - if (!boards.length) { list.innerHTML = '
검색 결과 없음
'; return; } - list.innerHTML = boards.map(b => { + if (!boards.length && !langFiltered.length) { list.innerHTML = '
검색 결과 없음
'; return; } + list.innerHTML = langHtml + boards.map(b => { const sel = b.fqbn === _csbSelBoard.fqbn; const qemuBadge = b.qemu === 'esp8266-native' ? `🖥 Native`