# RCSA DRONE Firmware ◆ Drone Light Show

หน้าเว็บ dashboard สวยๆ สำหรับ **อัปโหลดเฟิร์มแวร์** ลงอุปกรณ์ของ RCSA drone light show
แยกเป็น 3 ประเภทในการ์ดเดียวกัน:

| ประเภท | อุปกรณ์ | ไฟล์ | เครื่องมือ |
|------|---------|------|-----------|
| ✈ **ArduPilot** | Pixhawk flight controller | `.apj` | `vendor/px_uploader.py` |
| ⚙ **Parameters** | ArduPilot params (MAVLink) | `.param` | `vendor/param_uploader.py` |
| 📡 **SiK Radio** | Telemetry / RFD900 | `.ihx` | `vendor/sik_uploader.py` |
| ⚡ **ESP32** | Swarm node | `.bin` | `esptool` |

## วิธีใช้

1. ดับเบิลคลิก **`run.bat`** (หรือสั่ง `python server.py`)
2. เบราว์เซอร์จะเปิดที่ `http://127.0.0.1:8770` อัตโนมัติ
3. เลือก **พอร์ต** ด้านบนขวา (กด ⟳ เพื่อรีเฟรช)
4. ในการ์ดที่ต้องการ เลือก **ไฟล์เฟิร์มแวร์** (ระบบสแกนหาให้อัตโนมัติจากโฟลเดอร์ `RCSA_Upload`)
5. กด **FLASH** แล้วดู log สดในคอนโซลด้านล่าง

## หมายเหตุแต่ละประเภท

- **ArduPilot** — เสียบ Pixhawk ผ่าน USB แล้วกด FLASH ตัว uploader จะ reboot เข้า bootloader เอง
- **Parameters** — ต้อง **flash firmware ก่อน + ปล่อยให้บอร์ดบูตเสร็จ** แล้วค่อยเขียน param
  (คนละกลไกกับ flash — คุยผ่าน MAVLink) USB ใช้ baud `115200`, ผ่านวิทยุใช้ `57600`
  เขียนทีละตัวแล้วอ่านกลับมายืนยัน เสร็จแล้วแนะนำรีบูตบอร์ด 1 ครั้ง
- **SiK** — ตั้ง baud (ปกติ `57600`); ติ๊ก *reset params* ถ้าต้องการล้างค่ากลับ default
- **ESP32** — ต้อง build/export ไฟล์ `.bin` ก่อน
  - แอปอย่างเดียว (Arduino export) → flash ที่ `0x10000`
  - ภาพรวม merged (bootloader+partition+app) → flash ที่ `0x0`

## โครงสร้าง

```
RCSA_Firmware/
├─ server.py            backend (stdlib http.server + SSE)
├─ run.bat              ตัวเปิดโปรแกรม (ลง deps + รัน)
├─ requirements.txt     pyserial, esptool
├─ vendor/              uploader เดิมที่พิสูจน์แล้ว
│  ├─ px_uploader.py    (ArduPilot)
│  └─ sik_uploader.py   (SiK radio)
├─ web/                 หน้า dashboard neon
│  ├─ index.html
│  ├─ style.css
│  └─ app.js
└─ projects/
   └─ dronelightshow.json   แผนที่เฟิร์มแวร์ของโปรเจคนี้
```

## รันเป็น server บน Raspberry Pi (public)

ค่าเริ่มต้น bind `127.0.0.1` (เครื่องตัวเองเท่านั้น = ปลอดภัย). ถ้าจะให้เข้าจากเครื่องอื่น/อินเทอร์เน็ตผ่าน RPi
ให้ bind `0.0.0.0` **และตั้ง token เสมอ** (ไม่งั้นใครก็ยิงเฟิร์มแวร์เข้ามาได้):

```bash
python3 server.py --host 0.0.0.0 --port 8770 --token <รหัสลับ> --no-browser \
        --fw-root /home/pi/RCSA_Upload
```

เปิดจากเครื่องอื่น: `http://<ip-ของ-rpi>:8770/?token=<รหัสลับ>`
(หน้าเว็บจะหยิบ token จาก URL ไปแนบกับทุก API call ให้เอง)

ตั้งค่าผ่าน environment variable ก็ได้: `RCSA_HOST`, `RCSA_PORT`, `RCSA_TOKEN`, `RCSA_FW_ROOT`

รันเป็น service ถาวร (systemd) — `/etc/systemd/system/rcsa-firmware.service`:

```ini
[Unit]
Description=RCSA firmware server
After=network.target

[Service]
WorkingDirectory=/home/pi/RCSA_Upload/RCSA_Firmware
ExecStart=/usr/bin/python3 server.py --host 0.0.0.0 --token CHANGE_ME --no-browser
Restart=on-failure
User=pi

[Install]
WantedBy=multi-user.target
```
แล้ว `sudo systemctl enable --now rcsa-firmware`

> **ความปลอดภัย:** ตัวนี้รันคำสั่ง flash จริงบนพอร์ต serial ของ RPi — อย่าเปิดสู่อินเทอร์เน็ตตรงๆ โดยไม่มี token
> และควรอยู่หลัง VPN / reverse-proxy (เช่น Caddy/Nginx ที่มี HTTPS) ถ้าจะ public จริง

บน Linux พอร์ตจะเป็น `/dev/ttyACM0`, `/dev/ttyUSB0` — ผู้ใช้ต้องอยู่ในกลุ่ม `dialout`
(`sudo usermod -aG dialout $USER` แล้ว login ใหม่)

## กระจายงานหลายเครื่อง — flash พร้อมกันได้ (Distributed)

แนวคิด: **เครื่องหลัก (ของคุณ) = คลังเฟิร์มแวร์** ส่วนเครื่องอื่นๆ ที่มีบอร์ดเสียบอยู่
รัน `RCSA_DRONE_Firmware.exe` (ไม่ต้องลง Python) แล้ว **ดึง fw จากเครื่องหลักมา flash ลงบอร์ดของตัวเอง**
หลายเครื่องทำพร้อมกันได้ — แต่ละเครื่อง flash บอร์ดตัวเอง ดึงไฟล์จากคลังกลางเครื่องเดียว

```
                ┌─────────────────────────────┐
                │  เครื่องหลัก (คลัง fw)        │
                │  server.py --host 0.0.0.0    │
                │  --token rcsa2026            │
                └──────────────┬──────────────┘
                  ดึง fw ผ่าน IP │ (HTTP + token)
        ┌──────────────┬────────┴───────┬──────────────┐
   ┌────┴────┐    ┌────┴────┐      ┌────┴────┐    ┌────┴────┐
   │ เครื่อง A │    │ เครื่อง B │      │ เครื่อง C │    │  ...    │
   │ .exe +   │    │ .exe +   │      │ .exe +   │    │         │
   │ บอร์ด     │    │ บอร์ด     │      │ บอร์ด     │    │         │
   └─────────┘    └─────────┘      └─────────┘    └─────────┘
```

### ฝั่งเครื่องหลัก (คลัง fw)
1. รัน [run_public.bat](run_public.bat) (เปิด `--host 0.0.0.0 --token rcsa2026`)
2. ครั้งแรกรัน [open_firewall.bat](open_firewall.bat) เปิดพอร์ต 8770 (ขอ admin)
3. จด IP เครื่องนี้ (ดูจากหน้าจอตอนรัน เช่น `172.16.10.19`)

### ฝั่งเครื่องอื่น (ที่มีบอร์ด)
1. คัดลอก `dist\RCSA_DRONE_Firmware.exe` ไปเครื่องนั้น → ดับเบิลคลิก (ไม่ต้องลง Python)
2. ในหน้าเว็บ กดแถบ **🌐 เครื่องหลัก (Remote)** → ใส่ `http://172.16.10.19:8770` + token `rcsa2026` → **เชื่อมต่อ**
3. dropdown จะโชว์ไฟล์ fw จากเครื่องหลัก (ติด 🌐) → เลือกพอร์ต COM ของตัวเอง → **FLASH**
   (เครื่องจะดาวน์โหลด fw จากคลังมา cache แล้ว flash ลงบอร์ดที่เสียบเครื่องนี้)

> firmware ตัวจริงอยู่ที่เครื่องหลักเสมอ เครื่องอื่นแค่ดึงสำเนาชั่วคราวมา flash

## Build .exe เอง

ดับเบิลคลิก [build_exe.bat](build_exe.bat) (หรือดูคำสั่งในไฟล์) → ได้ `dist\RCSA_DRONE_Firmware.exe`
ตัวเดียวจบ มี Python + esptool + pymavlink + uploader ทั้งหมด bundle ในตัว
(ตอน frozen ตัว .exe เรียกตัวเองเป็น `__subtool__` เพื่อรัน uploader แต่ละตัว)

## เพิ่มโปรเจคใหม่

RCSA Firmware สแกนไฟล์เฟิร์มแวร์อัตโนมัติจากทั้งโฟลเดอร์ `RCSA_Upload` —
แค่วางไฟล์ `.apj` / `.ihx` / `.bin` ไว้ในโฟลเดอร์โปรเจคใดก็ได้ แล้วมันจะโผล่ใน dropdown เอง
ถ้าจะเปลี่ยน root ที่สแกน แก้ตัวแปร `FIRMWARE_ROOT` ใน `server.py`
