feat: Integrate AVR8js microcontroller simulator into Elemes LMS with custom compilation and simulation workflow

master
a2nr 2026-04-03 14:20:41 +07:00
parent 09827bf3ff
commit 5f57e67a25
1 changed files with 387 additions and 83 deletions

View File

@ -1,123 +1,427 @@
# Proposal: Studi Kelayakan dan Perencanaan Implementasi CircuitJS1 di Elemes LMS # Proposal: Integrasi AVR8js (Simulator Mikrokontroler AVR) ke Elemes LMS
## Pendahuluan ## Pendahuluan
Dokumen ini merupakan proposal dan studi kelayakan untuk mengintegrasikan **[CircuitJS1](https://github.com/pfalstad/circuitjs1)** (sebuah simulator rangkaian elektronik berbasis web) ke dalam ekosistem Elemes LMS. Tujuannya adalah untuk mentransisikan atau menambahkan kapabilitas LMS yang saat ini fokus pada pemrograman (Code Editor) menjadi platform pembelajaran rangkaian elektronik yang interaktif.
Dokumen ini merupakan proposal untuk mengintegrasikan **[avr8js](https://github.com/wokwi/avr8js)** — sebuah simulator mikrokontroler AVR 8-bit berbasis JavaScript — ke dalam ekosistem Elemes LMS. Referensi implementasi diambil dari **[Falstad Circuit Simulator + AVR8js](https://www.falstad.com/circuit/avr8js/index.html)**.
Tujuannya: siswa dapat menulis kode C/Arduino, meng-compile, dan mensimulasikan eksekusi pada mikrokontroler virtual — lengkap dengan koneksi ke simulator rangkaian CircuitJS1 yang sudah ada.
--- ---
## 1. Cara Implementasi dengan Sistem Elemes yang Sekarang ## 1. Apakah Memerlukan Compile Custom?
Sistem Elemes saat ini terdiri dari Backend (Flask) dan Frontend (SvelteKit). Implementasi CircuitJS1 dapat dilakukan dengan mulus karena CircuitJS1 berjalan sepenuhnya di sisi klien (browser). **Ya, memerlukan kompilasi khusus.**
### a. Integrasi Frontend (SvelteKit) AVR8js adalah *execution engine* saja — ia menjalankan machine code AVR yang sudah dikompilasi (format Intel HEX). Library ini **tidak menyertakan compiler**. Oleh karena itu:
- **Komponen Baru (`CircuitEditor.svelte`):** Komponen `CodeEditor.svelte` (berbasis CodeMirror) akan diganti atau didampingi dengan komponen baru yang memuat CircuitJS1.
- **Metode Embed:** CircuitJS1 dapat diintegrasikan menggunakan elemen `<iframe>` (dengan file HTML bawaan CircuitJS) yang disematkan di dalam halaman `/lesson/[slug]`. Alternatif lainnya adalah me-load file JavaScript CircuitJS secara langsung ke dalam DOM container SvelteKit.
- **Manajemen State (Auto-save):** CircuitJS1 memiliki fitur *Export/Import as Text*. Teks representasi rangkaian ini akan diperlakukan sama seperti "kode sumber" pada sistem saat ini. Teks tersebut dapat disimpan ke dalam `sessionStorage` (untuk auto-save) dan di-load kembali saat halaman di-refresh.
### b. Peran Backend (Flask) | Aspek | Penjelasan |
- Karena kompilasi dan simulasi berjalan di browser (menggunakan JavaScript/HTML5), fungsi kompilasi di backend (`/api/compile` dan *compiler factory*) tidak lagi diperlukan untuk pelajaran elektronik. |-------|-----------|
- Backend hanya perlu fokus pada *API proxy*, autentikasi token (`/api/login`), penyajian konten pelajaran, dan pencatatan progres (`/api/track-progress`). | **Compiler yang dibutuhkan** | `avr-gcc` (toolchain AVR), bukan `gcc` biasa |
| **Solusi yang dipilih** | **PlatformIO** — mengelola `avr-gcc` + Arduino core secara otomatis |
| **Lokasi kompilasi** | Backend (Flask) — sama seperti alur compile C yang sudah ada |
| **Output kompilasi** | Intel HEX string, dikirim ke frontend via JSON response |
| **Eksekusi** | Frontend (browser) — avr8js menjalankan HEX di browser |
### Alur Kerja
```
┌──────────────┐ POST /api/compile ┌──────────────────┐
│ Code Editor │ ──── {code, language} ────→ │ Flask Backend │
│ (SvelteKit) │ │ + PlatformIO │
└──────────────┘ └────────┬─────────┘
↑ │
│ {success, hex: "..."} │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ Browser: avr8js │
│ ┌─────────┐ USART ┌───────────────┐ │
│ │ CPU │ ──────→ │ Output Panel │ (Serial) │
│ │ Timer │ │ (Console) │ │
│ │ GPIO │ ──────→ │ CircuitJS1 │ (LED, dll) │
│ └─────────┘ └───────────────┘ │
└──────────────────────────────────────────────────────┘
```
--- ---
## 2. Cara Sistem Melakukan Evaluasi Terhadap Rangkaian Siswa ## 2. Dua Mode Bahasa: C Standar (avr-libc) & Arduino C++
Pada sistem pemrograman C/Python, evaluasi dilakukan dengan menangkap `stdout` (Output) dari eksekusi kode di backend. Untuk rangkaian listrik, evaluasi dipindah ke **sisi klien (Frontend)** dengan dua pendekatan yang bisa digabungkan: Sistem mendukung dua mode pemrograman, ditentukan per-lesson melalui `active_tabs`:
### a. Pendekatan Statis (Pencocokan Teks/Komponen) ### a. Mode AVR-C (avr-libc)
CircuitJS merepresentasikan rangkaian dalam bentuk string teks baris per baris. - Tag: `active_tabs` mengandung `'avr'`
- Saat pengguna menekan tombol **"Submit" / "Cek Rangkaian"**, SvelteKit akan meminta teks representasi rangkaian dari iframe CircuitJS. - Sintaks: `#include <avr/io.h>`, manipulasi register langsung (`PORTB`, `DDRB`, dll.)
- Sistem akan mengecek ketersediaan komponen-komponen wajib menggunakan fitur yang mengadopsi mekanisme `---KEY_TEXT---` saat ini. Misalnya, memastikan ada resistor (`r`), sumber tegangan (`v`), atau LED dalam teks rangkaian siswa. - PlatformIO framework: `none` (bare-metal avr-libc)
- Cocok untuk: pelajaran arsitektur mikrokontroler, register-level programming
### b. Pendekatan Dinamis (Pencocokan Nilai Simulasi) ```c
Karena CircuitJS disajikan secara *Same-Origin* (satu *domain/port* dengan SvelteKit), Elemes dapat mengakses langsung API global dari simulator tersebut tanpa batasan CORS. #include <avr/io.h>
#include <util/delay.h>
Dengan pendekatan ini, data yang dimasukkan instruktur pada tag `---EXPECTED_STATE---` adalah berformat **JSON** yang mendefinisikan kriteria kelulusan simulasi. int main(void) {
DDRB |= (1 << PB5); // Pin 13 sebagai output
**Contoh Format JSON `---EXPECTED_STATE---` di Markdown**: while (1) {
```json PORTB ^= (1 << PB5); // Toggle LED
{ _delay_ms(500);
"nodes": { }
"TestPoint_A": { "voltage": 5.0, "tolerance": 0.5 }
},
"elements": {
"Resistor_1": { "voltage_drop": 2.5 }
}
} }
``` ```
Sistem SvelteKit (melalui JavaScript) secara periodik akan mengekstrak state aktual komponen dengan merujuk pada **[Dokumentasi jsinterface CircuitJS1 (GitHub)](https://github.com/pfalstad/circuitjs1/blob/master/war/jsinterface.html)** atau melalui **[Live Example Interaktifnya](https://www.falstad.com/circuit/jsinterface.html)**: ### b. Mode Arduino C++
1. Menarik API Simulator: `var sim = iframe.contentWindow.CircuitJS1;` - Tag: `active_tabs` mengandung `'arduino'`
2. **`sim.getNodeVoltage(String n)`**: Mengambil nilai tegangan spesifik pada node observasi (misal node berlabel `TestPoint_A`). - Sintaks: `setup()`, `loop()`, `digitalWrite()`, `Serial.println()`, dll.
3. **`sim.getElements()`**: Mengambil sekumpulan *array* objek komponen yang aktif di *canvas*. Frontend kemudian akan memanipulasinya (contoh pencarian berdasarkan indeks/teks properti) lalu memanggil properti internal seperti `.getVoltage(0)` atau *current*-nya. - PlatformIO framework: `arduino` (include Arduino core library)
- Cocok untuk: pelajaran pemula, rapid prototyping
- SvelteKit mencocokkan kondisi aktual simulator vs ekspektasi JSON. (*Contoh: Apakah tegangan di TestPoint_A masuk dalam range 4.5V s.d. 5.5V?*) ```cpp
- Jika seluruh evaluasi menyatakan **LULUS**, maka SvelteKit mengirimkan HTTP request `POST /api/track-progress` ke Flask Backend untuk mencatat kelulusan siswa, lalu memunculkan *CelebrationOverlay* (kembang api). void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(13, HIGH);
Serial.println("LED ON");
delay(500);
digitalWrite(13, LOW);
Serial.println("LED OFF");
delay(500);
}
```
--- ---
## 3. Mengikuti Pola Pembuatan Konten yang Sekarang (Markdown) ## 3. Implementasi dengan Sistem Tab yang Sudah Ada
Salah satu keunggulan arsitektur Elemes saat ini adalah kemudahan membuat konten hanya dengan file Markdown (`.md`) dan pemisah teks (delimiter). **Pola ini dapat dipertahankan 100% tanpa mengubah struktur parser backend secara masif.** Sistem tab Elemes saat ini (`info | exercise | editor | circuit | output`) dimanfaatkan sepenuhnya:
Pembuat konten (guru) cukup membuat rangkaian di CircuitJS versi publik, melakukan *Export as Text*, lalu memasukkannya ke dalam format Markdown Elemes. | Tab | Fungsi untuk AVR |
|-----|------------------|
| **Editor** | Menulis kode AVR-C atau Arduino C++. CodeMirror 6 sudah support `lang-cpp`. |
| **Circuit** | CircuitJS1 iframe — rangkaian terhubung ke pin AVR via bridge. |
| **Output** | Serial console — menampilkan output USART dari avr8js (seperti `Serial.println()`). |
**Pemetaan Delimiter Markdown Baru:** ### Integrasi Tab di `active_tabs`
| Tipe C/C++ (Default) | Tipe Python (Baru) | Tipe Electronics | Tipe Kuis (Tambahan) | Keterangan / Fungsi pada Modul | Lesson markdown menentukan mode via tag konten:
|---|---|---|---|---| - `---INITIAL_CODE_AVR---` → aktifkan tab editor mode AVR-C
| `---LESSON_INFO---` | `---LESSON_INFO---` | `---LESSON_INFO---` | `---LESSON_INFO---` | Sama. Berisi tujuan pembelajaran. | - `---INITIAL_CODE_ARDUINO---` → aktifkan tab editor mode Arduino
| `---EXERCISE---` | `---EXERCISE---` | `---EXERCISE---` | `---EXERCISE---` | Sama. Soal instruksi untuk siswa. | - `---INITIAL_CIRCUIT---` → aktifkan tab circuit (sudah ada)
| `---INITIAL_CODE---` | `---INITIAL_PYTHON---` | `---INITIAL_CIRCUIT---` | `---INITIAL_QUIZ---` | Initial blok kode, simulator, atau *payload* kuis (JSON) saat dibuka. | - Keduanya bisa hadir bersamaan (hybrid lesson)
| `---SOLUTION_CODE---` | `---SOLUTION_PYTHON---` | `---SOLUTION_CIRCUIT---` | `---SOLUTION_QUIZ---` | Solusi akhir yang benar (kunci jawaban). |
| `---KEY_TEXT---` | `---KEY_TEXT---` | `---KEY_TEXT---` | `---KEY_TEXT---` | Komponen wajib atau validasi teks statis. |
| `---EXPECTED_OUTPUT---`| `---EXPECTED_OUTPUT---`| `---EXPECTED_STATE---` | `---EXPECTED_JSON---` | Output/Rules/Format evaluasi untuk hit *Track Progress*. |
### Konfigurasi Multi-Tab Workspace (Mode Hybrid) ### Flow Tombol "Run" untuk Mode AVR/Arduino
Agar sistem Elemes tahu antarmuka mana yang perlu dimuat, kita akan menggunakan **Pendekatan Implisit Kolektif**.
Alih-alih memaksa satu modul *hanya* menjadi "pelajaran C" atau "pelajaran Elektronika", parser SvelteKit dan Backend akan bersikap asimilatif. Jika seorang instruktur (misalnya untuk modul *Embedded System* berbekal AVR8js) memasukkan semua tag sekaligus ke dalam satu materi, sistem akan merender **Sistem Multi-Tab di Workspace**. 1. Ambil kode dari CodeEditor
2. POST ke `/api/compile` dengan `language: 'avr'` atau `'arduino'`
3. Backend compile via PlatformIO → return Intel HEX
4. Frontend parse HEX → load ke avr8js CPU memory
5. Jalankan simulation loop (60fps via requestAnimationFrame)
6. USART output → tampilkan di Output Panel sebagai serial console
7. GPIO changes → update CircuitJS1 via bridge
Cara kerjanya (Pendeteksian Paralel): ### Tombol Kontrol Tambahan
- Apakah `---INITIAL_CODE---` ada? -> Aktifkan Tab **CodeEditor (C/C++)**.
- Apakah `---INITIAL_PYTHON---` ada? -> Aktifkan Tab **CodeEditor (Python)**.
- Apakah `---INITIAL_CIRCUIT---` ada? -> Aktifkan Tab **CircuitEditor**.
- Apakah `---INITIAL_QUIZ---` ada? -> Aktifkan Tab **QuizPanel**.
Visi ini sangat **Backward Compatible** dan sangat visioner secara infrastruktur. Ratusan materi lama Anda yang secara konvensional hanya memiliki tag `_CODE` murni akan tetap tampil sebagai satu layar editor penuh C/C++. Sedangkan materi yang kompleks di masa depan bisa memadukan keempat fungsi (*C, Python, Simulator, Quiz*) dalam sistem tab yang elegan. - **Run**: Compile + Start simulation
- **Stop**: Hentikan simulation loop
- **Reset**: Stop + reset CPU state + clear serial output
**Workflow Pembuatan Konten oleh Guru:** ---
1. Buka CircuitJS di browser.
2. Gambar rangkaian "awal" (sebagian belum lengkap). Klik *File -> Export as Text*, salin ke dalam tag `---INITIAL_CIRCUIT---`.
3. Selesaikan rangkaiannya. Klik *Export as Text*, salin ke dalam tag `---SOLUTION_CIRCUIT---`.
4. Definisikan komponen yang diwajibkan di `---KEY_TEXT---`.
5. Siswa membuka Elemes LMS, SvelteKit mem-parsing string `INITIAL_CIRCUIT` dan menampilkannya sebagai rangkaian hidup di dalam CircuitJS.
## 4. Analisa Source Code & Refactoring Backend ## 4. Backend: PlatformIO sebagai Compiler Universal
Sistem `elemes/services/lesson_service.py` saat ini (`render_markdown_content`) memiliki parser *hardcoded* yang mengembalikan `7 item tuple` yang sangat restriktif. Menambahkan data elektronika ke *tuple* ini secara mentah akan menghasilkan rantai kembalian panjang (12+ item) yang rawan eror.
Oleh karena itu, bagian teknis dari proposal ini menyertakan perbaikan (*refactoring*) pada *blueprint* backend: ### Arsitektur Compiler Baru
### a. Modifikasi `elemes/services/lesson_service.py` File: `elemes/compiler/avr_compiler.py`
- Mengubah titik temu fungsi `render_markdown_content` menjadi tipe data **Dictionary** (*key-value*) bernama `parsed_data`.
- Menerapkan pola deteksi Kolektif: Fungsi *extract* akan memverifikasi ekstensi tag dan mengumpulkannya ke dalam *array* metadata, misal `active_tabs`.
- Jika `---INITIAL_CODE---` ada -> `active_tabs.append("c")`
- Jika `---INITIAL_PYTHON---` ada -> `active_tabs.append("python")`
- Jika `---INITIAL_CIRCUIT---` ada -> `active_tabs.append("circuit")`
- Jika `---INITIAL_QUIZ---` ada -> `active_tabs.append("quiz")`
### b. Modifikasi Router `elemes/routes/lessons.py` ```
- Menyesuaikan API endpoint `/lesson/[slug].json` agar memproses keluaran `active_tabs` ini dengan format JSON yang valid ke Frontend. BaseCompiler (base_compiler.py)
├── CCompiler (c_compiler.py) ← sudah ada
├── PythonCompiler (python_compiler.py) ← sudah ada
└── AVRCompiler (avr_compiler.py) ← BARU
├── mode 'avr' → PlatformIO framework=none
└── mode 'arduino' → PlatformIO framework=arduino
```
### c. Modifikasi Frontend SvelteKit (`elemes/frontend/src/routes/lesson/[slug]/+page.svelte`) ### Cara Kerja AVRCompiler
- Berdasarkan **analisa *source code* UI saat ini**, komponen *Workspace* Elemes sudah memiliki infrastruktur `<div class="panel-tabs">` dan skema *state* bawaan.
- *State type* bawaan `activeTab` yang semula hanya menampung tipe statis (`'info'|'exercise'|'editor'|'output'`) akan diperlebar menjadi dinamis (`'editor_c' | 'editor_python' | 'circuit' | 'quiz'`). 1. Buat temporary PlatformIO project directory
- SvelteKit cukup melacak *array* `active_tabs` rakitan backend untuk membangun komponen *tab/button* secara kondisional. Jika *array* lebih dari 1, *tab* aktif bergantian (*Embedded Systems Mode*). Jika *array* hanya 1 (pada file lama), antarmuka langsung kembali ke 100% *full-editor* seperti kondisi *legacy*. 2. Generate `platformio.ini`:
```ini
[env:uno]
platform = atmelavr
board = uno
framework = arduino ; atau kosong untuk avr-libc
```
3. Tulis source code ke `src/main.cpp` (Arduino) atau `src/main.c` (AVR-C)
4. Jalankan `pio run` → compile
5. Baca output `.hex` dari `.pio/build/uno/firmware.hex`
6. Return HEX string sebagai bagian dari JSON response:
```json
{
"success": true,
"hex": ":100000000C9462000C947E00...",
"output": "Compilation successful"
}
```
7. Cleanup temporary directory
### Response Format Baru
```typescript
interface CompileResponse {
success: boolean;
output: string; // stdout/stderr dari compiler
error: string; // error message jika gagal
hex?: string; // Intel HEX (hanya untuk avr/arduino)
}
```
### Perubahan Docker
```dockerfile
# Tambahan di elemes/Dockerfile
RUN pip install platformio
# Pre-cache PlatformIO packages (agar first compile cepat)
RUN mkdir -p /tmp/pio-warmup/src && \
echo '[env:uno]\nplatform = atmelavr\nboard = uno\nframework = arduino' \
> /tmp/pio-warmup/platformio.ini && \
echo 'void setup(){} void loop(){}' > /tmp/pio-warmup/src/main.cpp && \
cd /tmp/pio-warmup && pio run && \
rm -rf /tmp/pio-warmup
```
---
## 5. Frontend: AVR8js Simulation Engine
### Komponen Baru: `avr-simulator.ts`
File: `elemes/frontend/src/lib/services/avr-simulator.ts`
**Tanggung jawab:**
- Parse Intel HEX → `Uint16Array` (program memory 32KB)
- Inisialisasi avr8js CPU, Timer, USART
- Simulation loop via `requestAnimationFrame`
- Callback: `onSerialOutput(char)` — untuk serial console
- Callback: `onPortWrite(port, value)` — untuk GPIO bridge
**Intel HEX Parser:**
Format Intel HEX per baris: `:LLAAAATT[DD...]CC`
- `LL` = byte count
- `AAAA` = address
- `TT` = type (00=data, 01=EOF)
- `DD` = data bytes
- `CC` = checksum
**Simulation Loop:**
```
requestAnimationFrame →
run N instructions (16MHz / 60fps ≈ 266,666 cycles per frame) →
tick timers →
check USART output →
repeat
```
**Pertimbangan performa:**
- 266K cycles per frame cukup untuk real-time simulation
- Jika perlu, bisa dipindah ke Web Worker untuk non-blocking UI
- `delay()` di Arduino code berjalan secara natural karena timer simulation
---
## 6. Bridge: AVR8js ↔ CircuitJS1
### Mekanisme Koneksi
File: `elemes/frontend/src/lib/services/avr-circuit-bridge.ts`
Bridge menghubungkan pin AVR dengan elemen CircuitJS1 menggunakan API yang sudah tersedia:
| Arah | Mekanisme |
|------|-----------|
| **AVR → CircuitJS** | `cpu.writeHooks[PORTB]` mendeteksi GPIO write → `circuitApi.setExtVoltage(name, voltage)` |
| **CircuitJS → AVR** | `circuitApi.ontimestep` callback → `circuitApi.getNodeVoltage(name)` → set AVR PIN register |
### Konfigurasi Pin Map (per lesson)
Setiap lesson AVR+Circuit menyertakan JSON pin mapping di markdown:
```
---AVR_PIN_MAP---
{
"outputs": {
"PB5": { "extVoltageName": "arduino_d13", "type": "digital" }
},
"inputs": {
"PC0": { "circuitNode": "sensor_out", "type": "analog" }
}
}
---END_AVR_PIN_MAP---
```
**Cara kerja:**
- **Output (AVR → Circuit):** Saat AVR menulis ke PORTB bit 5, bridge memanggil `setExtVoltage("arduino_d13", 5.0)` atau `setExtVoltage("arduino_d13", 0.0)`.
- **Input (Circuit → AVR):** Setiap CircuitJS timestep, bridge membaca `getNodeVoltage("sensor_out")` dan set bit di register PIN AVR.
### Prasyarat untuk Lesson Author
Rangkaian CircuitJS harus menyertakan elemen **External Voltage** (ExtVoltageElm) dengan nama yang sesuai pin map. Contoh: elemen bernama `arduino_d13` mewakili output digital pin 13 Arduino.
---
## 7. Format Lesson Markdown — Marker Baru
### Marker Baru untuk AVR
| Marker | Fungsi |
|--------|--------|
| `---INITIAL_CODE_AVR---` | Kode awal mode AVR-C (avr-libc) |
| `---INITIAL_CODE_ARDUINO---` | Kode awal mode Arduino C++ |
| `---AVR_PIN_MAP---` | JSON konfigurasi pin mapping AVR ↔ CircuitJS |
| `---EXPECTED_SERIAL_OUTPUT---` | Expected serial output untuk auto-grading |
### Deteksi `active_tabs` (Backward Compatible)
Parser mendeteksi tag secara implisit (sama seperti sistem saat ini):
- `---INITIAL_CODE_AVR---` ada → `active_tabs.append('avr')`
- `---INITIAL_CODE_ARDUINO---` ada → `active_tabs.append('arduino')`
- Tag lama (`---INITIAL_CODE---`, `---INITIAL_CIRCUIT---`, dll.) tetap berfungsi tanpa perubahan.
### Contoh Lesson: Blink LED (Arduino)
```markdown
---LESSON_INFO---
Pelajaran Arduino: LED Blink dengan Simulator AVR.
- Memahami fungsi setup() dan loop()
- Mengontrol LED menggunakan pin digital
---END_LESSON_INFO---
# Blink LED
Program klasik Arduino: menyalakan dan mematikan LED bergantian.
---EXERCISE---
Buat program Arduino yang menyalakan LED selama 500ms dan mematikan selama 500ms.
Serial monitor harus menampilkan "ON" dan "OFF".
---
---INITIAL_CODE_ARDUINO---
void setup() {
// Inisialisasi pin 13 sebagai output
// Inisialisasi Serial
}
void loop() {
// Nyalakan LED, print "ON", delay 500ms
// Matikan LED, print "OFF", delay 500ms
}
---END_INITIAL_CODE_ARDUINO---
---INITIAL_CIRCUIT---
$ 1 0.000005 ...
v arduino_d13 ...
r 220 ...
162 ...
---END_INITIAL_CIRCUIT---
---EXPECTED_SERIAL_OUTPUT---
ON
OFF
---END_EXPECTED_SERIAL_OUTPUT---
---AVR_PIN_MAP---
{
"outputs": {
"PB5": { "extVoltageName": "arduino_d13", "type": "digital" }
},
"inputs": {}
}
---END_AVR_PIN_MAP---
---KEY_TEXT---
Serial.println
digitalWrite
---END_KEY_TEXT---
---SOLUTION_CODE---
void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(13, HIGH);
Serial.println("ON");
delay(500);
digitalWrite(13, LOW);
Serial.println("OFF");
delay(500);
}
---END_SOLUTION_CODE---
```
---
## 8. Evaluasi & Auto-Grading
Evaluasi lesson AVR menggunakan kombinasi metode yang sudah ada:
| Kriteria | Mekanisme | Existing? |
|----------|-----------|-----------|
| **Serial output** | Bandingkan USART output vs `expected_serial_output` | Adaptasi dari `expected_output` |
| **Node voltages** | `getNodeVoltage()` vs `expected_circuit_output` JSON | Sudah ada |
| **Key text** | Cek keyword wajib di source code | Sudah ada |
| **Hybrid AND** | Semua kriteria harus lulus | Sudah ada |
---
## 9. Perubahan File — Ringkasan
### File Baru
| File | Deskripsi |
|------|-----------|
| `elemes/compiler/avr_compiler.py` | PlatformIO compiler class |
| `frontend/src/lib/services/avr-simulator.ts` | AVR8js simulation engine + HEX parser |
| `frontend/src/lib/services/avr-circuit-bridge.ts` | Bridge GPIO ↔ CircuitJS1 |
| `content/blink_led.md` | Contoh lesson Arduino |
### File yang Dimodifikasi
| File | Perubahan |
|------|-----------|
| `elemes/compiler/__init__.py` | Register AVRCompiler |
| `elemes/services/lesson_service.py` | Parse marker AVR baru |
| `elemes/routes/lessons.py` | Tambah field AVR ke JSON response |
| `elemes/Dockerfile` | Install PlatformIO + warmup cache |
| `frontend/package.json` | Tambah dependency `avr8js` |
| `frontend/src/lib/types/lesson.ts` | Tambah field AVR |
| `frontend/src/lib/types/compiler.ts` | Tambah field `hex` |
| `frontend/src/lib/types/circuitjs.ts` | Tambah `setExtVoltage`, `ontimestep`, dll |
| `frontend/src/lib/components/WorkspaceHeader.svelte` | Tab AVR/Arduino |
| `frontend/src/routes/lesson/[slug]/+page.svelte` | Wire compile→simulate→output→bridge |
| `frontend/src/lib/components/OutputPanel.svelte` | Section serial console |
---
## 10. Potensi Tantangan & Mitigasi
| Tantangan | Mitigasi |
|-----------|---------|
| PlatformIO cold start lambat di Docker | Pre-cache packages saat `docker build` (warmup step) |
| avr8js tidak support semua peripheral | Untuk edukasi (LED, serial, digital I/O) sudah cukup. Dokumentasikan limitasi. |
| Sinkronisasi timing AVR ↔ CircuitJS | Keduanya berjalan real-time di browser event loop — natural sync |
| HEX file besar | Arduino sketch tipikal 5-50KB — cukup kecil untuk JSON response |
| CircuitJS `setExtVoltage` butuh elemen ExtVoltage | Lesson author wajib menyertakan elemen ini di initial circuit. Buat template. |
--- ---
## Kesimpulan ## Kesimpulan
Perubahan dari LMS pemrograman ke LMS simulasi rangkaian menggunakan CircuitJS1 **sangat feasible (layak)** dan **hemat sumber daya** karena:
1. Tidak membutuhkan komputasi simulasi berat di server (semua dilimpahkan ke client secara penuh). Integrasi AVR8js ke Elemes LMS **sangat layak** karena:
2. Mempertahankan gaya pembuatan konten berbasis Markdown yang *author-friendly*; menggunakan pendekatan pendeteksian tag *Implisit* (redundansi pengetikan nol, 100% backward-compatible dengan skenario C/Python lama).
3. Proses migrasinya sangat terpusat: hanya butuh merapikan *parser tuple-to-dictionary* di backend dan membuat *komponen UI tunggal iframe CircuitJS1* yang diletakkan pada SvelteKit frontend. 1. **Infrastruktur sudah siap** — Tab system, CircuitJS1 iframe, output panel, dan compiler factory sudah ada. AVR8js hanya menambah layer baru di atas fondasi yang kokoh.
2. **PlatformIO menyederhanakan toolchain** — Tidak perlu install avr-gcc manual; PlatformIO mengelola semua dependency secara otomatis dan support dua mode (avr-libc dan Arduino).
3. **Backward compatible** — Semua lesson C/Python yang sudah ada tidak terpengaruh. Deteksi tag implisit memastikan kompatibilitas penuh.
4. **Simulasi penuh di browser** — Setelah compile di backend, eksekusi sepenuhnya di client. Tidak membebani server.
5. **Bridge CircuitJS1 sudah feasible** — API `setExtVoltage` dan `getNodeVoltage` yang sudah ada di CircuitJS1 memungkinkan koneksi dua arah antara kode AVR dan simulasi rangkaian.