/*
 * hal_host.c — implementacion "simulada" de la capa de hardware (HAL).
 *
 * Permite escribir y probar programas de SiPi Electron en la
 * computadora, sin placa conectada: cada operacion de pin imprime
 * lo que haria en hardware real. Para correr sobre una placa de
 * verdad (Arduino/AVR, ESP32, etc.) se reemplaza este archivo por
 * un hal_avr.c / hal_esp32.c que hable con los registros o el SDK
 * correspondiente, sin tocar nada del lenguaje ni el interprete.
 */
#define _POSIX_C_SOURCE 200809L
#include "sipi_electron.h"
#include <stdio.h>
#include <time.h>

#define N_PINES 40
static int estado_pines[N_PINES];   /* 0/1 para digital, 0-255 para pwm */
static int modo_pines[N_PINES];     /* 0=entrada, 1=salida */

static int pin_valido(int pin) { return pin >= 0 && pin < N_PINES; }

void hal_pin_modo(int pin, int modo) {
    if (!pin_valido(pin)) { fprintf(stderr, "[hal] pin invalido: %d\n", pin); return; }
    modo_pines[pin] = modo;
    printf("[hal] pin %d configurado como %s\n", pin, modo ? "SALIDA" : "ENTRADA");
}

void hal_pin_escribir(int pin, int valor) {
    if (!pin_valido(pin)) { fprintf(stderr, "[hal] pin invalido: %d\n", pin); return; }
    estado_pines[pin] = valor ? 1 : 0;
    printf("[hal] pin %d -> %s\n", pin, valor ? "ALTO (1)" : "BAJO (0)");
}

int hal_pin_leer(int pin) {
    if (!pin_valido(pin)) return 0;
    printf("[hal] leyendo pin %d digital -> %d\n", pin, estado_pines[pin]);
    return estado_pines[pin];
}

int hal_analogico_leer(int pin) {
    /* En modo simulado devuelve un valor pseudo-estable basado en el pin,
     * asi los programas de ejemplo son reproducibles sin placa real. */
    int valor = (pin * 137) % 1024;
    printf("[hal] leyendo pin %d analogico -> %d\n", pin, valor);
    return valor;
}

void hal_pwm_escribir(int pin, int valor) {
    if (!pin_valido(pin)) { fprintf(stderr, "[hal] pin invalido: %d\n", pin); return; }
    if (valor < 0) valor = 0;
    if (valor > 255) valor = 255;
    estado_pines[pin] = valor;
    printf("[hal] pin %d PWM -> %d/255\n", pin, valor);
}

void hal_esperar_ms(int ms) {
    printf("[hal] esperando %d ms...\n", ms);
    if (ms > 0) {
        /* nanosleep en vez de usleep: no depende de macros POSIX que
         * puedan faltar segun el toolchain (evita 'implicit declaration
         * of usleep' en algunos entornos), y no tiene el limite de
         * usleep a esperas menores a 1 segundo. */
        struct timespec ts;
        ts.tv_sec = ms / 1000;
        ts.tv_nsec = (long)(ms % 1000) * 1000000L;
        nanosleep(&ts, NULL);
    }
}
