/*
 * sleep — заблокироваться на N секунд калиброванным busy-wait'ом (см.
 * _sleep_calib.c — общий движок с delayms()).
 *
 * Старая версия (50 halt = 1 c) предполагала, что КАЖДОЕ прерывание —
 * кадровый тик 50 Гц; с CBL/клавиатурой на векторе 0xFF это неверно
 * (CBL может прерывать в разы/десятки раз чаще кадра — sleep() вернулся
 * бы намного раньше срока).
 *
 * sleep(seconds) — вложенный цикл: внешний по секундам, внутренний
 * ровно 50 раз калиброванный _sleep_spin() — та же структура, что и в
 * старой версии (внешний секунды, внутренний 50×halt), только вместо
 * halt — калиброванный спин.  Umножения/32-бит арифметики нет.
 *
 * Fallback: если фрейм-хук уже занят другим irq_install()-клиентом
 * (EBUSY) — калибровку сделать некорректно, откатываемся к старому
 * "50 halt ~ 1 c" поведению для этого конкретного вызова.
 */

#include <unistd.h>
#include "_sleep_calib.h"

/* Старое поведение — фолбэк, если calibrate() не может безопасно
 * получить кадровый хук. */
static void _sleep_legacy(unsigned int seconds) __naked
{
    (void)seconds;
    __asm
    _slg_outer:
        ld    a, h
        or    l
        ret   Z
        ld    b, #50            ; 50 halt-ов ~ 1 c (при ЕДИНСТВЕННОМ
                                 ; источнике прерываний на векторе 0xFF)
    _slg_inner:
        halt
        djnz  _slg_inner
        dec   hl
        jr    _slg_outer
    __endasm;
}

void sleep(unsigned int seconds)
{
    if (seconds == 0) return;

    if (!_sleep_units_per_frame) _sleep_calibrate();

    if (!_sleep_units_per_frame) {
        _sleep_legacy(seconds);
        return;
    }

    while (seconds--) {
        uint8_t frame = 50;         /* 50 кадров ~ 1 с при 50 Гц */
        while (frame--) {
            _sleep_spin(_sleep_units_per_frame);
        }
    }
}
