#include #include #include #include #include #include #include #include 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; }