Files
up_go/utils/WriteUbootToDevices.go
T
2026-03-19 14:07:10 +07:00

154 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package utils
import (
"fmt"
"io"
"os"
"strconv"
"sync"
"syscall"
"up/utils/mtd"
)
// Глобальное состояние загрузки (используется для обновления прогресса)
var uploadState struct {
sync.RWMutex
Progress int
// другие поля могут быть здесь
}
// writeUbootToDevices записывает U-Boot в файл, SPI NOR и SD-карту.
// Принимает данные, их длину и путь для сохранения копии в файловой системе.
func WriteUbootToDevices(data []byte, filepath string) error {
UBOOT_MAX_SIZE, err := strconv.Atoi(os.Getenv("UBOOT_MAX_SIZE"))
if err != nil {
fmt.Println("error: ", err)
return err
}
MMC_BOOT_OFFSET, err := strconv.Atoi(os.Getenv("MMC_BOOT_OFFSET"))
if err != nil {
fmt.Println("error: ", err)
return err
}
const chunkSize = 4096
dataLen := int64(len(data))
fmt.Printf("Writing U-Boot to devices (%d bytes)...\n", dataLen)
// Проверка лимита размера
if dataLen > int64(UBOOT_MAX_SIZE*1024*1024) {
return fmt.Errorf("U-Boot image too large for SPI NOR (%d > %d bytes)", dataLen, UBOOT_MAX_SIZE)
}
// --- 1. Сохраняем в файл (копия) ---
f, err := os.Create(filepath)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", filepath, err)
}
var written int64
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
n, err := f.Write(data[written : written+toWrite])
if err != nil {
f.Close()
return fmt.Errorf("failed to write to file: %w", err)
}
written += int64(n)
// Прогресс: 30% за запись в файл
uploadState.Lock()
uploadState.Progress = int(written * 30 / dataLen)
uploadState.Unlock()
}
f.Close()
syscall.Sync() // синхронизация после записи файла
// --- 2. Запись в SPI NOR (/dev/mtd0) ---
fmt.Println("Writing to /dev/mtd0 (SPI NOR)...")
mtdFd, err := os.OpenFile("/dev/mtd0", os.O_RDWR|os.O_SYNC, 0660)
if err == nil {
defer mtdFd.Close()
// Получаем размер MTD-устройства из sysfs
mtdSize, err := mtd.ReadMTDSize(0)
if err != nil {
fmt.Printf("Cannot get MTD size from sysfs, proceeding without erase: %v\n", err)
} else {
// Стираем весь чип
fmt.Printf("Erasing SPI NOR (size %d bytes)...\n", mtdSize)
if err := mtd.EraseMTD(mtdFd, 0, mtdSize); err != nil {
fmt.Printf("Warning: erase failed (continuing anyway): %v\n", err)
} else {
fmt.Println("SPI NOR erased successfully")
}
}
// Запись в MTD
written = 0
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
n, err := mtdFd.Write(data[written : written+toWrite])
if err != nil {
fmt.Printf("Error writing to /dev/mtd0: %v\n", err)
break
}
written += int64(n)
// Прогресс: 30–65% за SPI NOR
uploadState.Lock()
uploadState.Progress = 30 + int(written*35/dataLen)
uploadState.Unlock()
}
fmt.Printf("Written %d bytes to /dev/mtd0\n", written)
} else {
fmt.Printf("/dev/mtd0 not available: %v (skipping SPI NOR)\n", err)
}
// --- 3. Запись в SD-карту (/dev/mmcblk1) со смещением 8 КБ ---
fmt.Printf("Writing to /dev/mmcblk1 at offset %d (SD card boot area)...\n", MMC_BOOT_OFFSET)
mmcFd, err := os.OpenFile("/dev/mmcblk1", os.O_RDWR|os.O_SYNC, 0660)
if err == nil {
defer mmcFd.Close()
// Устанавливаем смещение
if _, err := mmcFd.Seek(int64(MMC_BOOT_OFFSET), io.SeekStart); err != nil {
fmt.Printf("Failed to seek on /dev/mmcblk1: %v\n", err)
} else {
written = 0
for written < dataLen {
toWrite := dataLen - written
if toWrite > chunkSize {
toWrite = chunkSize
}
n, err := mmcFd.Write(data[written : written+toWrite])
if err != nil {
fmt.Printf("Error writing to /dev/mmcblk1: %v\n", err)
break
}
written += int64(n)
// Прогресс: 65–100% за MMC
uploadState.Lock()
uploadState.Progress = 65 + int(written*35/dataLen)
uploadState.Unlock()
}
fmt.Printf("Written %d bytes to /dev/mmcblk1 at offset %d\n", written, MMC_BOOT_OFFSET)
}
} else {
fmt.Printf("/dev/mmcblk1 not available: %v (skipping SD card)\n", err)
}
// Финальная синхронизация
syscall.Sync()
uploadState.Lock()
uploadState.Progress = 100
uploadState.Unlock()
return nil
}