You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
3.8 KiB
C

#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <unistd.h>
static void print_json_error(const char *message)
{
printf("{\"success\":false,\"error\":\"%s\"}\n", message);
}
static void close_bus(int fd, int lock_fd)
{
if (fd >= 0)
{
close(fd);
}
flock(lock_fd, LOCK_UN);
close(lock_fd);
}
int main(int argc, char *argv[])
{
if (argc < 5 || argc > 6 ||
(argc == 6 && strcmp(argv[5], "--no-response") != 0))
{
print_json_error("Uso: EZO_COMMAND bus address delay_ms command [--no-response]");
return 2;
}
const char *bus = argv[1];
char *address_end = NULL;
char *delay_end = NULL;
long address_value = strtol(argv[2], &address_end, 0);
long delay_value = strtol(argv[3], &delay_end, 10);
const char *command = argv[4];
size_t command_length = strlen(command);
int no_response = argc == 6;
if (*argv[2] == '\0' || *address_end != '\0' || address_value < 1 || address_value > 127)
{
print_json_error("Direccion I2C no valida (1-127)");
return 2;
}
if (*argv[3] == '\0' || *delay_end != '\0' || delay_value < 0 || delay_value > 60000)
{
print_json_error("Delay no valido (0-60000 ms)");
return 2;
}
if (command_length == 0 || command_length > 63)
{
print_json_error("Comando EZO no valido (1-63 bytes)");
return 2;
}
int lock_fd = open("/tmp/photobioreactor-i2c.lock", O_CREAT | O_RDWR, 0660);
if (lock_fd < 0 || flock(lock_fd, LOCK_EX) < 0)
{
print_json_error("No se pudo bloquear el bus I2C");
if (lock_fd >= 0)
{
close(lock_fd);
}
return 3;
}
int fd = open(bus, O_RDWR);
if (fd < 0)
{
print_json_error("No se pudo abrir el bus I2C");
close_bus(fd, lock_fd);
return 4;
}
if (ioctl(fd, I2C_SLAVE, (int)address_value) < 0)
{
print_json_error("No se pudo seleccionar el circuito EZO");
close_bus(fd, lock_fd);
return 5;
}
if (write(fd, command, command_length) != (ssize_t)command_length)
{
print_json_error("Fallo al escribir el comando EZO");
close_bus(fd, lock_fd);
return 6;
}
usleep((useconds_t)delay_value * 1000);
if (no_response)
{
printf("{\"success\":true,\"response\":\"SENT\"}\n");
close_bus(fd, lock_fd);
return 0;
}
unsigned char response[64] = {0};
int bytes_read = read(fd, response, sizeof(response) - 1);
for (int retry = 0; bytes_read > 0 && response[0] == 254 && retry < 10; retry++)
{
usleep(100000);
memset(response, 0, sizeof(response));
bytes_read = read(fd, response, sizeof(response) - 1);
}
if (bytes_read < 1)
{
print_json_error("El circuito EZO no respondio");
close_bus(fd, lock_fd);
return 7;
}
if (response[0] != 1)
{
char message[64];
const char *detail = response[0] == 2 ? "error de sintaxis" :
response[0] == 254 ? "procesando, timeout" :
response[0] == 255 ? "sin datos" : "desconocido";
snprintf(message, sizeof(message), "Codigo EZO %u: %s", response[0], detail);
print_json_error(message);
close_bus(fd, lock_fd);
return 8;
}
char *payload = (char *)&response[1];
payload[bytes_read > 1 ? bytes_read - 1 : 0] = '\0';
for (int index = 0; payload[index] != '\0'; index++)
{
if (payload[index] == '"' || payload[index] == '\\')
{
payload[index] = ' ';
}
}
printf("{\"success\":true,\"response\":\"%s\"}\n",
payload[0] == '\0' ? "*OK" : payload);
close_bus(fd, lock_fd);
return 0;
}