UNPKG

@toponextech/smartembed-mcp-server

Version:

MCP server for intelligent embedded development with PlatformIO - AI-powered project creation, error diagnosis, and device detection

314 lines 12.3 kB
"use strict"; /** * Device Parser for SmartEmbed * Parses PlatformIO device list output and extracts device information */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DeviceParser = void 0; // Common board identification patterns const BOARD_PATTERNS = [ // ESP32 variants { patterns: [/CP210[0-9]/i, /Silicon Labs/i], boards: ['esp32dev', 'esp32-c3-devkitm-1', 'esp32-s2-devkitm-1'], manufacturer: 'Silicon Labs', boardType: 'ESP32', confidence: 'high', }, { patterns: [/CH340/i, /CH341/i], boards: ['esp32dev', 'nodemcu-32s', 'wemos_d1_mini32', 'uno', 'nodemcuv2'], manufacturer: 'WCH', boardType: 'ESP32/ESP8266/Arduino', confidence: 'low', // CH340 is used by many different boards }, // ESP8266 variants { patterns: [/NodeMCU/i, /CP210[0-9].*NodeMCU/i], boards: ['nodemcuv2', 'nodemcu', 'esp12e'], boardType: 'ESP8266', confidence: 'high', }, { patterns: [/Wemos.*D1/i, /WEMOS/i], boards: ['d1_mini', 'd1_mini_pro', 'd1'], boardType: 'ESP8266', confidence: 'high', }, // Arduino boards { patterns: [/Arduino.*Uno/i, /2341:0043/i, /2341:0001/i], boards: ['uno'], boardType: 'Arduino', confidence: 'high', }, { patterns: [/Arduino.*Mega/i, /2341:0042/i, /2341:0010/i], boards: ['megaatmega2560', 'megaatmega1280'], boardType: 'Arduino', confidence: 'high', }, { patterns: [/Arduino.*Nano/i, /Arduino.*Nano.*Every/i], boards: ['nano', 'nanoatmega328', 'nano_every'], boardType: 'Arduino', confidence: 'high', }, { patterns: [/Arduino.*Leonardo/i, /2341:8036/i], boards: ['leonardo'], boardType: 'Arduino', confidence: 'high', }, // STM32 boards { patterns: [/STM32.*Nucleo/i, /0483:374[0-9]/i], boards: ['nucleo_f103rb', 'nucleo_f401re', 'nucleo_f411re'], boardType: 'STM32', confidence: 'high', }, { patterns: [/STM32/i, /STMicroelectronics/i, /0483:/i], boards: ['genericSTM32F103C8', 'bluepill_f103c8', 'blackpill_f401cc'], boardType: 'STM32', confidence: 'medium', }, // Raspberry Pi Pico { patterns: [/Raspberry.*Pi.*Pico/i, /2e8a:0005/i, /RP2040/i], boards: ['pico', 'nanorp2040connect'], boardType: 'RP2040', confidence: 'high', }, // Generic FTDI { patterns: [/FTDI/i, /FT232/i, /0403:6001/i], boards: ['uno', 'pro16MHzatmega328', 'pro8MHzatmega328'], boardType: 'Generic', confidence: 'low', connectionTips: ['This appears to be an FTDI adapter. Make sure it\'s connected to your board correctly.'], }, ]; // VID:PID database for quick lookup const VID_PID_DATABASE = { '2341:0043': { boards: ['uno'], confidence: 'high' }, '2341:0042': { boards: ['megaatmega2560'], confidence: 'high' }, '2341:8036': { boards: ['leonardo'], confidence: 'high' }, '1a86:7523': { boards: ['uno', 'esp32dev', 'nodemcuv2'], confidence: 'low' }, '10c4:ea60': { boards: ['esp32dev', 'esp32-c3-devkitm-1'], confidence: 'medium' }, '0403:6001': { boards: ['uno', 'pro16MHzatmega328'], confidence: 'low' }, '2e8a:0005': { boards: ['pico'], confidence: 'high' }, '0483:374b': { boards: ['nucleo_f103rb'], confidence: 'high' }, }; class DeviceParser { /** * Parse PlatformIO device list output */ parseDeviceList(output) { const devices = []; const lines = output.split('\n'); let currentDevice = null; for (const line of lines) { const trimmedLine = line.trim(); // Windows format: COM3 - USB Serial Device (COM3) const windowsMatch = trimmedLine.match(/^(COM\d+)\s*-\s*(.+)$/); if (windowsMatch) { if (currentDevice) { devices.push(this.finalizeDevice(currentDevice)); } currentDevice = { port: windowsMatch[1], description: windowsMatch[2], hwid: '', }; continue; } // Unix format: /dev/ttyUSB0 - CP2102 USB to UART Bridge Controller const unixMatch = trimmedLine.match(/^(\/dev\/[^\s]+)\s*-\s*(.+)$/); if (unixMatch) { if (currentDevice) { devices.push(this.finalizeDevice(currentDevice)); } currentDevice = { port: unixMatch[1], description: unixMatch[2], hwid: '', }; continue; } // Hardware ID line if (trimmedLine.startsWith('HWID:') || trimmedLine.startsWith('Hardware ID:')) { const hwid = trimmedLine.replace(/^(HWID:|Hardware ID:)\s*/i, ''); if (currentDevice) { currentDevice.hwid = hwid; this.parseHwid(hwid, currentDevice); } } // Description line (indented) - but skip HWID continuation lines if ((trimmedLine.startsWith('desc:') || /^\s+/.test(line)) && !trimmedLine.startsWith('SER:') && !trimmedLine.startsWith('LOCATION:') && !trimmedLine.startsWith('HWID:') && !trimmedLine.startsWith('Hardware ID:')) { const desc = trimmedLine.replace(/^desc:\s*/i, '').trim(); if (currentDevice && desc && desc !== currentDevice.description) { // Only update description if it's different currentDevice.description = desc; } } } // Don't forget the last device if (currentDevice) { devices.push(this.finalizeDevice(currentDevice)); } return devices; } /** * Parse hardware ID to extract VID/PID and other info */ parseHwid(hwid, device) { // Extract VID:PID - handle both formats let vidPidMatch = hwid.match(/VID:PID=([0-9A-Fa-f]{4}):([0-9A-Fa-f]{4})/i); if (!vidPidMatch) { // Try Windows format: VID_1234&PID_5678 vidPidMatch = hwid.match(/VID_([0-9A-Fa-f]{4})&PID_([0-9A-Fa-f]{4})/i); } if (vidPidMatch) { device.vid = vidPidMatch[1].toUpperCase(); device.pid = vidPidMatch[2].toUpperCase(); } // Extract serial number const serialMatch = hwid.match(/SER=([^\s\\]+)/i); if (serialMatch) { device.serialNumber = serialMatch[1]; } // Extract location (for uniqueness) const locationMatch = hwid.match(/LOCATION=([^\s\\]+)/i); if (locationMatch) { // Store location in serialNumber if no serial found if (!device.serialNumber) { device.serialNumber = `LOC:${locationMatch[1]}`; } } } /** * Finalize device object with defaults */ finalizeDevice(device) { return { port: device.port || 'Unknown', description: device.description || 'Unknown Device', hwid: device.hwid || '', manufacturer: device.manufacturer, product: device.product, serialNumber: device.serialNumber, vid: device.vid, pid: device.pid, boardType: device.boardType, suggestedBoard: device.suggestedBoard, }; } /** * Identify board type based on device information */ identifyBoard(device) { let bestMatch = null; // First, try VID:PID lookup if (device.vid && device.pid) { const vidPid = `${device.vid}:${device.pid}`.toLowerCase(); const match = VID_PID_DATABASE[vidPid]; if (match) { bestMatch = { board: match.boards[0], confidence: match.confidence, alternatives: match.boards.slice(1), tips: [], }; } } // Then try pattern matching on description and HWID for (const pattern of BOARD_PATTERNS) { const matchText = `${device.description} ${device.hwid}`; const matches = pattern.patterns.some(p => p.test(matchText)); if (matches) { // If we already have a high confidence match, skip if (bestMatch && bestMatch.confidence === 'high' && pattern.confidence !== 'high') { continue; } bestMatch = { board: pattern.boards[0], confidence: pattern.confidence, alternatives: pattern.boards.slice(1), tips: pattern.connectionTips || [], }; // Store board type in device device.boardType = pattern.boardType; device.suggestedBoard = pattern.boards[0]; // If high confidence, we're done if (pattern.confidence === 'high') { break; } } } // If no match found, provide generic suggestions if (!bestMatch) { return { detectedBoard: 'unknown', confidence: 'low', alternativeBoards: ['uno', 'esp32dev', 'nodemcuv2', 'nucleo_f103rb'], connectionTips: [ 'Could not identify the board automatically.', 'Try specifying the board manually with: pio boards', 'Make sure the board is properly connected and drivers are installed.', ], }; } // Generate connection tips based on board type const tips = [...bestMatch.tips]; if (device.boardType === 'ESP32' || device.boardType === 'ESP8266') { tips.push('Make sure you have the correct USB drivers installed (CP2102, CH340, etc.)'); tips.push('Some boards require holding the BOOT button when uploading'); } if (device.boardType === 'STM32') { tips.push('STM32 boards may require STM32CubeProgrammer or DFU mode for first upload'); tips.push('Check the BOOT0 jumper position if upload fails'); } return { detectedBoard: bestMatch.board, confidence: bestMatch.confidence, alternativeBoards: bestMatch.alternatives, connectionTips: tips, }; } /** * Generate connection suggestions based on device analysis */ generateConnectionSuggestions(devices) { const suggestions = []; if (devices.length === 0) { suggestions.push('No devices detected. Please check:'); suggestions.push('- Board is connected via USB'); suggestions.push('- USB cable supports data (not charge-only)'); suggestions.push('- Drivers are installed (check Device Manager on Windows)'); suggestions.push('- Try a different USB port'); return suggestions; } if (devices.length > 1) { suggestions.push(`Found ${devices.length} devices. To specify which one to use:`); suggestions.push(`- Add to platformio.ini: upload_port = ${devices[0].port}`); suggestions.push('- Or use: pio run -t upload --upload-port <port>'); } // Check for common issues for (const device of devices) { if (device.description.includes('FTDI') || device.description.includes('FT232')) { suggestions.push('FTDI adapter detected - ensure TX/RX connections are correct (TX→RX, RX→TX)'); } if (device.port.includes('Bluetooth')) { suggestions.push('Bluetooth port detected - for programming, use USB connection instead'); } } return suggestions; } } exports.DeviceParser = DeviceParser; //# sourceMappingURL=device-parser.js.map