|
1 | 1 | import { useEffect, useRef, useState } from 'react' |
2 | 2 |
|
3 | | -import { FlashManager, StepCode, ErrorCode, DeviceType } from '../utils/manager' |
| 3 | +import { FlashManager, StepCode, ErrorCode, DeviceType, DUMP_GPT_MODE } from '../utils/manager' |
4 | 4 | import { useImageManager } from '../utils/image' |
5 | 5 | import { isLinux, isWindows } from '../utils/platform' |
6 | 6 | import config from '../config' |
@@ -517,6 +517,91 @@ function LinuxUnbind({ onNext }) { |
517 | 517 | ) |
518 | 518 | } |
519 | 519 |
|
| 520 | +// GPT Dump diagnostic mode |
| 521 | +function GptDumpMode({ qdlManager, imageManager }) { |
| 522 | + const [gptDump, setGptDump] = useState(null) |
| 523 | + const [loading, setLoading] = useState(false) |
| 524 | + const [copied, setCopied] = useState(false) |
| 525 | + const [ready, setReady] = useState(false) |
| 526 | + |
| 527 | + useEffect(() => { |
| 528 | + if (!imageManager.current) return |
| 529 | + fetch(config.loader.url) |
| 530 | + .then((res) => res.arrayBuffer()) |
| 531 | + .then((programmer) => { |
| 532 | + qdlManager.current = new FlashManager(programmer, {}) |
| 533 | + qdlManager.current.initialize(imageManager.current).then(() => setReady(true)) |
| 534 | + }) |
| 535 | + }, [imageManager.current]) |
| 536 | + |
| 537 | + const handleDump = async () => { |
| 538 | + setLoading(true) |
| 539 | + const result = await qdlManager.current.dumpGpt() |
| 540 | + setGptDump(result) |
| 541 | + setLoading(false) |
| 542 | + } |
| 543 | + |
| 544 | + const handleCopy = () => { |
| 545 | + navigator.clipboard.writeText(gptDump) |
| 546 | + setCopied(true) |
| 547 | + setTimeout(() => setCopied(false), 2000) |
| 548 | + } |
| 549 | + |
| 550 | + return ( |
| 551 | + <div className="flex flex-col items-center justify-center h-full gap-6 p-8"> |
| 552 | + <div className="text-center"> |
| 553 | + <h1 className="text-3xl font-bold mb-2">GPT Diagnostic Mode</h1> |
| 554 | + <p className="text-xl text-gray-600"> |
| 555 | + Connect your device to dump partition table info |
| 556 | + </p> |
| 557 | + </div> |
| 558 | + |
| 559 | + {!gptDump ? ( |
| 560 | + <button |
| 561 | + onClick={handleDump} |
| 562 | + disabled={loading || !ready} |
| 563 | + className={`px-8 py-3 text-xl font-semibold rounded-full transition-colors ${ |
| 564 | + loading || !ready |
| 565 | + ? 'bg-gray-300 text-gray-500 cursor-not-allowed' |
| 566 | + : 'bg-[#51ff00] hover:bg-[#45e000] active:bg-[#3acc00] text-black' |
| 567 | + }`} |
| 568 | + > |
| 569 | + {loading ? 'Reading...' : !ready ? 'Initializing...' : 'Connect & Dump GPT'} |
| 570 | + </button> |
| 571 | + ) : ( |
| 572 | + <> |
| 573 | + <textarea |
| 574 | + readOnly |
| 575 | + value={gptDump} |
| 576 | + className="w-full max-w-3xl h-96 p-4 font-mono text-sm bg-gray-900 text-gray-100 rounded-lg" |
| 577 | + /> |
| 578 | + <div className="flex gap-4"> |
| 579 | + <button |
| 580 | + onClick={handleCopy} |
| 581 | + className="px-6 py-2 text-lg font-semibold rounded-full bg-blue-600 hover:bg-blue-500 text-white transition-colors" |
| 582 | + > |
| 583 | + {copied ? 'Copied!' : 'Copy to Clipboard'} |
| 584 | + </button> |
| 585 | + <button |
| 586 | + onClick={() => setGptDump(null)} |
| 587 | + className="px-6 py-2 text-lg font-semibold rounded-full bg-gray-300 hover:bg-gray-400 text-black transition-colors" |
| 588 | + > |
| 589 | + Dump Again |
| 590 | + </button> |
| 591 | + </div> |
| 592 | + <p className="text-gray-500"> |
| 593 | + Send this to{' '} |
| 594 | + <a href="https://discord.comma.ai" target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline"> |
| 595 | + Discord |
| 596 | + </a> |
| 597 | + {' '}for debugging |
| 598 | + </p> |
| 599 | + </> |
| 600 | + )} |
| 601 | + </div> |
| 602 | + ) |
| 603 | +} |
| 604 | + |
520 | 605 | // WebUSB connection screen - shows while waiting for user to select device |
521 | 606 | function WebUSBConnect({ onConnect }) { |
522 | 607 | return ( |
@@ -722,6 +807,11 @@ export default function Flash() { |
722 | 807 | // Handle retry on error |
723 | 808 | const handleRetry = () => window.location.reload() |
724 | 809 |
|
| 810 | + // Render GPT dump diagnostic mode |
| 811 | + if (DUMP_GPT_MODE) { |
| 812 | + return <GptDumpMode qdlManager={qdlManager} imageManager={imageManager} /> |
| 813 | + } |
| 814 | + |
725 | 815 | // Render landing page |
726 | 816 | if (wizardScreen === 'landing' && !error) { |
727 | 817 | return ( |
|
0 commit comments