# Çalışma modları ve bellek

Her proje satırında bir **N / T / S** cipi vardır. Tıkla, sırayla değişir; seçim dosyaya kaydedilir (`config.json` `modlar`). Varsayılan **N**. Seçili dosyanın çubuğu: **Kaydet · N|T|S · Çalıştır/Durdur (tek düğme) · Sil**; koşarken Durdur olur, S seçiliyse "Solo başlat".

## Üç mod

| Mod | Nasıl koşar | Heap | Dahili DRAM | Ne için |
|---|---|---|---|---|
| **N Normal** | Tek ortak iş parçacığında asyncio görevi | 2–15 KB | **0** (ortak çalışan bir kez 17 KB) | LED, sensör, küçük sayfa: çoğu proje |
| **T Thread** | Kendi FreeRTOS thread'i, GIL ile dilimli (yalnız ESP32) | aynı | 10–15 KB | Ekran çizen, sleep'siz sıkı döngü, ağır hesap |
| **S Solo** | Panel kapalı, kart yeniden başlar, tek proje | hepsi | hepsi | BLE, HTTPS |

**Normal mod nasıl çalışır:** proje dosyası satır satır `async def` içine sarılır, üst düzey adlar `global` ilan edilir, `cyd.sleep(` → `await`, `time.sleep(` → `await`. Sonuç geçici dosyaya akıtılır ve `execfile` ile dosyadan derlenir; 12 KB'lik kaynak string olarak heap'e hiç girmez. Bekleme çağrısı bir `def` gövdesindeyse dönüşüm uymaz (MicroPython `await`'i düz `def` içinde sessizce generator'a çevirir, gövde hiç çalışmaz); ön tarama bunu yakalar ve proje **kendiliğinden T'de açılır**, log nedenini yazar. `async def` yazarsan dokunulmaz, `main()` koroutini çalıştırılır.

**Solo** tek seferliktir: `main.py` bayrağı ilk iş olarak siler; RESET'e basınca panel geri gelir. Panel: dosyayı seç → S → Çalıştır → WiFi açık/kapalı sorusu. API: `POST /api/solo?name=<dosya>&wifi=0|1`.

## İki bellek

ESP32'de iki ayrı cep vardır ve kritik olan ikincisi:

| | |
|---|---|
| MicroPython heap | Projelerin verisi, `gc.mem_free()` |
| **Dahili DRAM** | WiFi, soketler, thread yığınları, BLE, TLS. `cyd.dram()` |

`gc.mem_free()` bol görünürken thread açılamayabilir ya da BLE/TLS `ENOMEM` verebilir. Doğru ölçüm panelin sistem kutusu ya da `cyd.dram()`.

| CYD | Stok v1.28.0 | **CYD Studio firmware'i** |
|---|---|---|
| Dahili DRAM boş, panel açık | 27,8 KB | **55 KB** |
| Python heap boş | 80 / 137 (otomatik büyür, DRAM'i yutar) | 75 / 94 (**sabit 96 KB**) |
| Aynı anda proje | 1 (ikincisi `can't create thread`) | 7 normal + 2–3 thread |

Firmware ne yaptı: 12 çekirdek modülü flash'a dondu; heap sabitlendi (otomatik ikiye katlama 2 küçük projeyle DRAM'i 76 → 12 KB'ye düşürüyordu); lwIP/WiFi tamponları küçüldü; canlı log halkası 250 → 100 satır (250 satır 20,7 KB tutup heap'i parçalıyordu); sunucu soket zaman aşımı 5 saniye.

Thread yığını dahili DRAM'den çıkar: proje başına 10–15 KB. Ekran çizen proje heap'ten 25–33 KB alır (durunca geri gelir). Sızıntı yok: aynı proje 4 kez aç/kapat → 65,7 / 65,7 / 65,9 / 65,8 KB.

## Ölçüldü: yan yana projeler (CYD)

| Sırayla açılan | Heap'ten | DRAM'den | Koşan |
|---|---|---|---|
| yuk_kontrol (12 KB kaynak + `/yuk` rotaları) | 12,2 KB | **17,3 KB** (ortak çalışan, bir kez) | 1 |
| led_yakip_sondur | 2,2 | 0 | 2 |
| gece_lambasi | 8,2 | 0,3 | 3 |
| ornek_led | 4,7 | 0 | 4 |
| isik_olcum | 7,7 | 0 | 5 |
| harici_led | 7,1 | 0 | 7 |
| ornek_isik_sensoru (ekrana çizer) | **33 KB** → heap 1 KB | 0 | 8 |

Yedi küçük proje yan yana, dahili RAM 37 KB'de sabit; sınır artık heap. Heap'i büyütmek gerekirse `frozen_esp32_build.py --heap 112` (DRAM 55 → 39 KB, yine 2 thread sığar).

## Gerçekten yan yana mı?

10 ms'de bir tur atan "buton yoklayıcı" proje, turlar arası en uzun boşluk (15 saniye):

| Senaryo | ortalama | en uzun | >100 ms boşluk |
|---|---|---|---|
| Tek başına, normal | 12,9 ms | 21 ms | 0 |
| + 4 normal proje (LED/LDR) | 15,9 | 352 | 5 |
| + ekrana çizen proje (normal) | 25,5 | **973** | 33 |
| + thread'de %90 CPU hesap | 211 | **3405** | 5 |
| Aynı yük, yoklayıcı **T** modunda | 12,0 | **37** | 0 |

Okuma: LED/sensör komşularıyla normal mod gerçekten dönüşümlü. **Ekrana çizen proje normal modda kötü komşudur** (SPI dolgusu tek iş parçacığını ~1 sn tutar): T yap. **CPU'yu bırakmayan thread** normal çalışanı aç bırakır: ağır döngüye `cyd.sleep(0.001)` koy ya da giriş projesini T yap. Buton için asıl yol yoklama değil `cyd.buton` (kesme).

## Durdurma ve bekçi

Thread izolasyon sağlamaz: MicroPython'un GIL'i var, aynı anda tek thread bytecode çalıştırır. CPU'yu bırakmayan bir proje paneli aç bırakır. Buna karşı:

1. Sunucu her turda nabız yazar; dinleyici soket zaman aşımlıdır ki `accept()` nabzı durdurmasın.
2. İlk iş başlayınca bir bekçi thread'i açılır, 2 saniyede bir nabza bakar.
3. Panel 20 saniye nabız vermezse çalışan projelere durdurma bayrağı.
4. Proje 4 saniyede durmazsa `machine.reset()`. Panel her koşulda geri gelir; doğrulandı: boğan proje 28. saniyede durduruldu, panel 302 ms'ye döndü.

## ESP8266'da

`_thread` yok. N = sunucunun asyncio döngüsünde görev (T cipi gizli), S var. Ölçüldü: 3 normal proje yan yana, heap 19 → 9 KB (proje başına 2,5–5 KB), panel en uzun 0,69 sn. Pratik sınır 3 proje. `cyd.sleep()` çağırmayan proje için zamanlayıcı kesicisi 100 ms'de bir bakar, 400 ms'dir pompa dönmediyse sunucu turunu iki bytecode arasına sokar; `while True: x += 1` koşarken 6/6 durum sorgusu cevaplandı. Durdurma isteği 4,5 saniyeyi aşarsa loga `!!! yanit vermiyor` yazılıp kart resetlenir (~10 sn'de panel geri gelir).
