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.

189 lines
3.9 KiB
C

#include <errno.h>
#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>
typedef struct
{
const char *name;
int address;
double value;
int valid;
int enabled;
} sensor_t;
static int sensor_matches(const sensor_t *sensor, const char *name)
{
return strcmp(sensor->name, name) == 0 ||
(strcmp(sensor->name, "temperature") == 0 && strcmp(name, "rtd") == 0);
}
static void enable_requested_sensors(sensor_t *sensors, size_t sensor_count, int argc, char *argv[])
{
if (argc == 2)
{
for (size_t index = 0; index < sensor_count; index++)
{
sensors[index].enabled = 1;
}
return;
}
for (int arg = 2; arg < argc; arg++)
{
for (size_t index = 0; index < sensor_count; index++)
{
if (sensor_matches(&sensors[index], argv[arg]))
{
sensors[index].enabled = 1;
}
}
}
}
static int select_sensor(int fd, int address)
{
return ioctl(fd, I2C_SLAVE, address);
}
static int request_reading(int fd, sensor_t *sensor)
{
const char command = 'R';
if (select_sensor(fd, sensor->address) < 0)
{
return -1;
}
if (write(fd, &command, 1) != 1)
{
return -1;
}
sensor->valid = -1;
return 0;
}
static int receive_reading(int fd, sensor_t *sensor)
{
unsigned char response[64] = {0};
if (select_sensor(fd, sensor->address) < 0)
{
return -1;
}
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 < 2 || response[0] != 1)
{
return -1;
}
response[bytes_read] = '\0';
char *end = NULL;
errno = 0;
double value = strtod((char *)&response[1], &end);
if (errno != 0 || end == (char *)&response[1])
{
return -1;
}
sensor->value = value;
sensor->valid = 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stderr, "Uso: EZO_ACQUIRE /dev/i2c-1 [temperature|ph|do|ec]\n");
return 2;
}
sensor_t sensors[] = {
{"temperature", 0x66, 0.0, 0, 0},
{"ph", 0x63, 0.0, 0, 0},
{"do", 0x61, 0.0, 0, 0},
{"ec", 0x64, 0.0, 0, 0}};
const size_t sensor_count = sizeof(sensors) / sizeof(sensors[0]);
enable_requested_sensors(sensors, sensor_count, argc, argv);
int lock_fd = open(
"/tmp/photobioreactor-i2c.lock",
O_CREAT | O_RDWR,
0660);
if (lock_fd < 0 || flock(lock_fd, LOCK_EX) < 0)
{
fprintf(stderr, "No se pudo bloquear el bus I2C\n");
return 3;
}
int fd = open(argv[1], O_RDWR);
if (fd < 0)
{
fprintf(stderr, "No se pudo abrir %s\n", argv[1]);
flock(lock_fd, LOCK_UN);
close(lock_fd);
return 4;
}
for (size_t index = 0; index < sensor_count; index++)
{
if (sensors[index].enabled)
{
request_reading(fd, &sensors[index]);
}
}
usleep(1000000);
for (size_t index = 0; index < sensor_count; index++)
{
if (sensors[index].valid == -1)
{
receive_reading(fd, &sensors[index]);
}
}
printf("{");
for (size_t index = 0; index < sensor_count; index++)
{
printf(
"%s\"%s\":",
index == 0 ? "" : ",",
sensors[index].name);
if (sensors[index].valid == 1)
{
printf("%.6f", sensors[index].value);
}
else
{
printf("null");
}
}
printf("}\n");
close(fd);
flock(lock_fd, LOCK_UN);
close(lock_fd);
return 0;
}