#![no_std]
#![no_main]

use esp32_hal::{
    clock::ClockControl,
    delay::Ets,
    gpio::{IO, Pins},
    pac::Peripherals,
    prelude::*,
    timer::TimerGroup,
    Rtc,
};

const SERVO_PIN: usize = 17; // Предположим, что сервопривод подключен к GPIO17

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take().unwrap();
    let system = peripherals.DPORT.split();
    let clocks = ClockControl::max(system.clock_control).freeze();

    let mut rtc = Rtc::new(peripherals.RTC);
    rtc.swd.disable();
    rtc.rwdtn.disable();

    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let mut wdt0 = timer_group0.wdt;
    wdt0.disable();

    let pins = Pins::new(peripherals.GPIO, peripherals.IO_MUX);
    let mut servo_pin = pins.gpio17.into_push_pull_output();

    loop {
        move_servo(&mut servo_pin, 0);  // повернуть в крайнюю левую позицию
        Ets::delay_ms(1000);
        move_servo(&mut servo_pin, 90); // повернуть в среднее положение
        Ets::delay_ms(1000);
        move_servo(&mut servo_pin, 180); // повернуть в крайнюю правую позицию
        Ets::delay_ms(1000);
    }
}

// Функция перемещения сервопривода в определенное положение
fn move_servo(pin: &mut impl OutputPin, position: u16) {
    // Приведение позиции к диапазону широтно-импульсной модуляции (PWM)
    let duty = map(position, 0, 180, 500, 2500); // от 500 до 2500 микросекунд
    pwm_output(pin, duty as f32 / 1000.0); // конвертация в миллисекунды
}

// Линейная функция преобразования угла в ширину импульса
fn map(value: u16, in_min: u16, in_max: u16, out_min: u16, out_max: u16) -> u16 {
    ((value - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}

// Генерация PWM сигнала с указанной длительностью
fn pwm_output(pin: &mut impl OutputPin, duty_cycle: f32) {
    use std::thread::sleep;
    use std::time::Duration;

    let period = Duration::from_secs_f32(duty_cycle); // Длительность активного периода (HIGH)
    let pause = Duration::from_millis(20); // Длительность неактивного периода (LOW)

    pin.set_high().unwrap(); // Активный период
    sleep(period);
    pin.set_low().unwrap(); // Неактивный период
    sleep(pause);
}