Merge pull request 'up some deprecated fixes' (#2) from develop into main
Build / Build (push) Successful in 11s
Build / Build (push) Successful in 11s
Reviewed-on: TolaMironcenko/up_go#2
This commit was merged in pull request #2.
This commit is contained in:
+2
-2
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"up/utils"
|
||||
@@ -26,7 +27,6 @@ func ExtlinuxRead(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
// В случае ошибки кодирования уже ничего не сделать,
|
||||
// можно только залогировать (здесь опущено для краткости)
|
||||
fmt.Errorf("Encoding error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
var MOUNT_POINT = os.Getenv("MOUNT_POINT")
|
||||
var EXTLINUX_FILE = os.Getenv("EXTLINUX_FILE")
|
||||
// Ограничиваем размер тела, чтобы избежать слишком больших запросов (аналог 4096 в C)
|
||||
r.Body = http.MaxBytesReader(w, r.Body, 4096)
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@@ -24,7 +23,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Парсим JSON
|
||||
var requestData struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
@@ -35,7 +33,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Проверяем наличие поля content
|
||||
if requestData.Content == "" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
@@ -45,14 +42,12 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
timestamp := r.URL.Query().Get("timestamp")
|
||||
if timestamp != "" {
|
||||
// Полное URL-декодирование (в C декодировался только %3A, но здесь используем стандартный способ)
|
||||
decoded, err := url.QueryUnescape(timestamp)
|
||||
if err == nil {
|
||||
timestamp = decoded
|
||||
}
|
||||
}
|
||||
|
||||
// Монтируем устройство
|
||||
if utils.MountDevice() < 0 {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -60,11 +55,9 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Формируем полный путь к файлу
|
||||
filePath := filepath.Join(MOUNT_POINT, EXTLINUX_FILE)
|
||||
fmt.Println(filePath)
|
||||
|
||||
// Открываем файл на запись (создаём/перезаписываем)
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -74,7 +67,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Записываем содержимое
|
||||
if _, err := f.WriteString(requestData.Content); err != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -86,7 +78,6 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
versionPath := filepath.Join(MOUNT_POINT, EXTLINUX_FILE+".version")
|
||||
vf, err := os.Create(versionPath)
|
||||
if err == nil {
|
||||
// Форматируем ISO 8601 в человекочитаемый вид (как в C)
|
||||
var readableDate string
|
||||
if len(timestamp) >= 19 {
|
||||
readableDate = timestamp[:10] + " " + timestamp[11:19] // "YYYY-MM-DD HH:MM:SS"
|
||||
@@ -99,10 +90,8 @@ func ExtlinuxWrite(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Принудительно сбрасываем файловые буферы на диск (аналог sync())
|
||||
syscall.Sync()
|
||||
|
||||
// Успешный ответ
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`{"status":"success","message":"extlinux.conf updated"}`))
|
||||
|
||||
+1
-8
@@ -8,33 +8,26 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// handleFiledate обрабатывает HTTP-запрос для получения даты файла (версии)
|
||||
func FileDate(w http.ResponseWriter, r *http.Request) {
|
||||
var MOUNT_POINT = os.Getenv("MOUNT_POINT")
|
||||
// Получаем параметр "file" из строки запроса
|
||||
filename := r.URL.Query().Get("file")
|
||||
if filename == "" {
|
||||
http.Error(w, `{"error":"Missing file parameter"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Формируем путь к файлу версии: <mount_point>/<filename>.version
|
||||
versionPath := filepath.Join(MOUNT_POINT, filename+".version")
|
||||
|
||||
// Пытаемся прочитать первую строку из файла версии
|
||||
dateStr := ""
|
||||
f, err := os.Open(versionPath)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
if scanner.Scan() {
|
||||
dateStr = scanner.Text() // считываем строку без символа новой строки
|
||||
dateStr = scanner.Text()
|
||||
}
|
||||
// Ошибки сканера игнорируем (как в C)
|
||||
}
|
||||
// Если файл не существует или другая ошибка — оставляем dateStr пустой
|
||||
|
||||
// Формируем JSON-ответ
|
||||
response := map[string]interface{}{
|
||||
"status": "success",
|
||||
"date": dateStr,
|
||||
|
||||
+1
-13
@@ -10,13 +10,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// MOUNT_POINT должен быть определён (например, как глобальная константа)
|
||||
// const MOUNT_POINT = "/mnt/mydevice"
|
||||
|
||||
// handleReboot обрабатывает HTTP-запрос на перезагрузку системы
|
||||
func HandleReboot(w http.ResponseWriter, r *http.Request) {
|
||||
MOUNT_POINT := os.Getenv("MOUNT_POINT")
|
||||
// Отправляем JSON-ответ (как в C: mg_http_reply)
|
||||
response := map[string]string{
|
||||
"status": "success",
|
||||
"message": "System rebooting...",
|
||||
@@ -27,26 +22,19 @@ func HandleReboot(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Синхронизируем все файловые системы (аналог sync())
|
||||
syscall.Sync()
|
||||
|
||||
// Размонтируем точку монтирования, если она смонтирована
|
||||
fmt.Printf("Unmounting %s...\n", MOUNT_POINT)
|
||||
if err := syscall.Unmount(MOUNT_POINT, 0); err != nil {
|
||||
// Ошибку не фатализируем, просто логируем
|
||||
fmt.Printf("Unmount error: %v\n", err)
|
||||
}
|
||||
|
||||
// Повторная синхронизация
|
||||
syscall.Sync()
|
||||
|
||||
// Инициируем мягкую перезагрузку через команду shutdown
|
||||
fmt.Println("Initiating soft reboot via shutdown...")
|
||||
|
||||
// Запускаем shutdown в отдельной горутине с небольшой задержкой,
|
||||
// чтобы ответ гарантированно ушёл клиенту до завершения сервера
|
||||
go func() {
|
||||
time.Sleep(500 * time.Millisecond) // ждём 0.5 секунды
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
cmd := exec.Command("shutdown", "-r", "now")
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Printf("Reboot failed: %v\n", err)
|
||||
|
||||
@@ -3,8 +3,8 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -15,44 +15,38 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
|
||||
// Thermal zones 0–3
|
||||
for i := 0; i < 4 && !success; i++ {
|
||||
tempPath := fmt.Sprintf("/sys/class/thermal/thermal_zone%d/temp", i)
|
||||
data, err := ioutil.ReadFile(tempPath)
|
||||
data, err := os.ReadFile(tempPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Читаем тип зоны, если доступен
|
||||
typePath := fmt.Sprintf("/sys/class/thermal/thermal_zone%d/type", i)
|
||||
typeData, _ := ioutil.ReadFile(typePath) // ошибку игнорируем
|
||||
typeData, _ := os.ReadFile(typePath)
|
||||
zoneType := strings.TrimSpace(string(typeData))
|
||||
|
||||
// Парсим температуру
|
||||
var tempRaw int
|
||||
if _, err := fmt.Sscanf(string(data), "%d", &tempRaw); err != nil {
|
||||
continue
|
||||
}
|
||||
temp := float64(tempRaw) / 1000.0
|
||||
|
||||
// Проверяем, является ли зона CPU/SOC
|
||||
isCPU := strings.Contains(strings.ToLower(zoneType), "cpu") ||
|
||||
strings.Contains(strings.ToLower(zoneType), "soc")
|
||||
|
||||
temperature = temp
|
||||
success = true
|
||||
if isCPU {
|
||||
break // предпочитаем CPU
|
||||
break
|
||||
}
|
||||
// иначе продолжаем искать CPU
|
||||
}
|
||||
|
||||
// Если thermal не дал результата, пробуем hwmon 0–3
|
||||
for i := 0; i < 4 && !success; i++ {
|
||||
tempPath := fmt.Sprintf("/sys/class/hwmon/hwmon%d/temp1_input", i)
|
||||
data, err := ioutil.ReadFile(tempPath)
|
||||
data, err := os.ReadFile(tempPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Читаем имя сенсора
|
||||
namePath := fmt.Sprintf("/sys/class/hwmon/hwmon%d/name", i)
|
||||
nameData, _ := ioutil.ReadFile(namePath)
|
||||
nameData, _ := os.ReadFile(namePath)
|
||||
sensorName := strings.TrimSpace(string(nameData))
|
||||
|
||||
var tempRaw int
|
||||
@@ -72,7 +66,6 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Финальный fallback – просто temp1_input для первых 4 hwmon
|
||||
if !success {
|
||||
fallbackPaths := []string{
|
||||
"/sys/class/hwmon/hwmon0/temp1_input",
|
||||
@@ -81,7 +74,7 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
|
||||
"/sys/class/hwmon/hwmon3/temp1_input",
|
||||
}
|
||||
for _, path := range fallbackPaths {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -95,7 +88,6 @@ func HandleTemperature(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Формируем JSON-ответ
|
||||
response := map[string]interface{}{
|
||||
"success": success,
|
||||
"temperature": temperature,
|
||||
|
||||
+4
-20
@@ -14,7 +14,6 @@ import (
|
||||
"up/utils"
|
||||
)
|
||||
|
||||
// Глобальное состояние загрузки (аналог g_upload в C)
|
||||
type UploadState struct {
|
||||
mu sync.RWMutex
|
||||
Type string
|
||||
@@ -25,7 +24,7 @@ type UploadState struct {
|
||||
|
||||
var uploadState UploadState
|
||||
|
||||
// handleUpload обрабатывает POST /api/upload
|
||||
// POST /api/upload
|
||||
func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
uboot_max_size_int, err := strconv.Atoi(os.Getenv("UBOOT_MAX_SIZE"))
|
||||
if err != nil {
|
||||
@@ -40,15 +39,13 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
UBOOT_MAX_SIZE := uboot_max_size_int * 1024 * 1024
|
||||
MAX_FILE_SIZE := max_file_size_int * 1024 * 1024
|
||||
MOUNT_POINT := os.Getenv("MOUNT_POINT")
|
||||
// Ограничиваем размер запроса (максимум UBOOT_MAX_SIZE + запас)
|
||||
r.Body = http.MaxBytesReader(w, r.Body, int64(MAX_FILE_SIZE)+1024)
|
||||
if err := r.ParseMultipartForm(32 << 20); err != nil { // 32 MB в памяти
|
||||
http.Error(w, `{"error":"Failed to parse multipart form"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.MultipartForm.RemoveAll() // очищаем временные файлы
|
||||
defer r.MultipartForm.RemoveAll()
|
||||
|
||||
// Получаем поле "type"
|
||||
typeVals := r.MultipartForm.Value["type"]
|
||||
if len(typeVals) == 0 {
|
||||
http.Error(w, `{"error":"Missing type field"}`, http.StatusBadRequest)
|
||||
@@ -56,7 +53,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
typ := typeVals[0]
|
||||
|
||||
// Получаем файл из поля "file"
|
||||
files := r.MultipartForm.File["file"]
|
||||
if len(files) == 0 {
|
||||
http.Error(w, `{"error":"Missing file field"}`, http.StatusBadRequest)
|
||||
@@ -64,7 +60,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
fileHeader := files[0]
|
||||
|
||||
// Проверка размера файла
|
||||
maxSize := int64(MAX_FILE_SIZE)
|
||||
if typ == "uboot_bin" {
|
||||
maxSize = int64(UBOOT_MAX_SIZE)
|
||||
@@ -74,7 +69,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Открываем загруженный файл
|
||||
srcFile, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
http.Error(w, `{"error":"Failed to open uploaded file"}`, http.StatusInternalServerError)
|
||||
@@ -82,13 +76,11 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// Монтируем устройство
|
||||
if utils.MountDevice() < 0 {
|
||||
http.Error(w, `{"error":"Failed to mount device"}`, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Определяем имя файла назначения
|
||||
filename := utils.GetTargetFilename(typ)
|
||||
if filename == "" {
|
||||
http.Error(w, `{"error":"Invalid upload type"}`, http.StatusBadRequest)
|
||||
@@ -96,7 +88,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
destPath := filepath.Join(MOUNT_POINT, filename)
|
||||
|
||||
// Обновляем состояние загрузки
|
||||
uploadState.mu.Lock()
|
||||
uploadState.Type = typ
|
||||
uploadState.Received = 0
|
||||
@@ -106,7 +97,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Printf("Upload: %s (%d bytes) -> %s\n", typ, fileHeader.Size, destPath)
|
||||
|
||||
// Получаем timestamp из query и декодируем
|
||||
timestamp := r.URL.Query().Get("timestamp")
|
||||
if timestamp != "" {
|
||||
decoded, err := url.QueryUnescape(timestamp)
|
||||
@@ -115,7 +105,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Специальная обработка для U-Boot
|
||||
if typ == "uboot_bin" {
|
||||
data, err := io.ReadAll(srcFile)
|
||||
if err != nil {
|
||||
@@ -139,7 +128,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
uploadState.Status = "Complete"
|
||||
uploadState.mu.Unlock()
|
||||
} else {
|
||||
// Обычная запись файла чанками с обновлением прогресса
|
||||
destFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
uploadState.mu.Lock()
|
||||
@@ -150,7 +138,7 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
buf := make([]byte, 65536) // 64 KB чанки
|
||||
buf := make([]byte, 65536) // 64 KB chunks
|
||||
var written int64
|
||||
for {
|
||||
n, err := srcFile.Read(buf)
|
||||
@@ -163,7 +151,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
written += int64(n)
|
||||
// Обновляем прогресс
|
||||
uploadState.mu.Lock()
|
||||
uploadState.Received = written
|
||||
uploadState.Progress = int(written * 100 / fileHeader.Size)
|
||||
@@ -181,19 +168,17 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
destFile.Sync()
|
||||
syscall.Sync() // глобальная синхронизация
|
||||
syscall.Sync()
|
||||
uploadState.mu.Lock()
|
||||
uploadState.Progress = 100
|
||||
uploadState.Status = "Complete"
|
||||
uploadState.mu.Unlock()
|
||||
}
|
||||
|
||||
// Запись файла версии с timestamp
|
||||
if timestamp != "" {
|
||||
versionPath := filepath.Join(MOUNT_POINT, filename+".version")
|
||||
vf, err := os.Create(versionPath)
|
||||
if err == nil {
|
||||
// Форматируем ISO 8601 в читаемый вид (как в C)
|
||||
var readableDate string
|
||||
if len(timestamp) >= 19 {
|
||||
readableDate = timestamp[:10] + " " + timestamp[11:19] // "YYYY-MM-DD HH:MM:SS"
|
||||
@@ -208,7 +193,6 @@ func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Printf("Upload complete: %s\n", destPath)
|
||||
|
||||
// Формируем JSON-ответ
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
|
||||
+2
-7
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -13,7 +14,6 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
|
||||
var DEVICE = os.Getenv("DEVICE")
|
||||
mounted := false
|
||||
|
||||
// Проверяем, смонтировано ли устройство, читая /proc/mounts
|
||||
f, err := os.Open("/proc/mounts")
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
@@ -25,10 +25,8 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Ошибки сканера игнорируем (аналогично C‑версии)
|
||||
}
|
||||
|
||||
// Формируем JSON‑ответ
|
||||
response := map[string]interface{}{
|
||||
"mounted": mounted,
|
||||
"mount_point": MOUNT_POINT,
|
||||
@@ -36,10 +34,7 @@ func MountStatus(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// json.NewEncoder автоматически добавляет символ новой строки в конце,
|
||||
// что соответствует формату "%s\n" в C.
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
// В случае ошибки кодирования уже ничего не сделать,
|
||||
// можно только залогировать (здесь опущено для краткости)
|
||||
fmt.Errorf("Encoding error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,11 @@ import (
|
||||
"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 {
|
||||
@@ -35,12 +31,10 @@ func WriteUbootToDevices(data []byte, filepath string) error {
|
||||
|
||||
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)
|
||||
@@ -48,36 +42,29 @@ func WriteUbootToDevices(data []byte, filepath string) error {
|
||||
|
||||
var written int64
|
||||
for written < dataLen {
|
||||
toWrite := dataLen - written
|
||||
if toWrite > chunkSize {
|
||||
toWrite = chunkSize
|
||||
}
|
||||
toWrite := min(dataLen-written, 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() // синхронизация после записи файла
|
||||
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)
|
||||
@@ -86,20 +73,15 @@ func WriteUbootToDevices(data []byte, filepath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Запись в MTD
|
||||
written = 0
|
||||
for written < dataLen {
|
||||
toWrite := dataLen - written
|
||||
if toWrite > chunkSize {
|
||||
toWrite = chunkSize
|
||||
}
|
||||
toWrite := min(dataLen-written, 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()
|
||||
@@ -109,29 +91,23 @@ func WriteUbootToDevices(data []byte, filepath string) error {
|
||||
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
|
||||
}
|
||||
toWrite := min(dataLen-written, 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()
|
||||
@@ -142,7 +118,6 @@ func WriteUbootToDevices(data []byte, filepath string) error {
|
||||
fmt.Printf("/dev/mmcblk1 not available: %v (skipping SD card)\n", err)
|
||||
}
|
||||
|
||||
// Финальная синхронизация
|
||||
syscall.Sync()
|
||||
|
||||
uploadState.Lock()
|
||||
|
||||
Reference in New Issue
Block a user