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

347 lines
7.3 KiB

/*
* [rpiezos]
* Nicola Pisanti, MIT License 2020
*/
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <lo/lo.h>
#define NUM_PIEZOS 6
struct piezo_t {
int enabled;
int min;
int max;
int mark;
float z1;
};
struct config_t {
long int sleep_usecs;
int verbose;
const char * ip;
const char * port;
const char * address;
};
void quit_handler(int signo);
int parse_args(int argc, char * argv[], struct piezo_t * piezos, struct config_t * config);
void usec_sleep(long int usecs);
int running = 1;
int main(int argc, char * argv[])
{
int rc = 0;
struct piezo_t piezos[NUM_PIEZOS];
for (unsigned i = 0; i < NUM_PIEZOS; ++i) {
piezos[i].enabled = 0;
piezos[i].min = 0;
piezos[i].max = 1024;
piezos[i].mark = 0;
piezos[i].z1 = -1;
}
struct config_t config;
config.ip = NULL;
config.port = NULL;
config.address = "/piezo";
config.verbose = 0;
config.sleep_usecs = 500;
// --------- args -------------------------
rc = parse_args(argc, argv, piezos, &config);
if (rc != 0) {
return rc;
}
for (int i = 0; i < NUM_PIEZOS; ++i) {
if (piezos[i].enabled) {
printf("[rpiezos] piezo %d enabled, range %d-%d\n", i,
piezos[i].min, piezos[i].max);
}
}
// --------- signal handling -------------
if (signal(SIGINT, quit_handler) == SIG_ERR) {
fprintf(stderr, "[rpiezos] Error on assigning signal handler\n");
return -1;
}
if (signal(SIGTERM, quit_handler) == SIG_ERR) {
fprintf(stderr, "[rpiezos] Error on assigning signal handler\n");
return -1;
}
// --------- mcp init --------------------
int spi_fd;
unsigned char mode;
unsigned char bits_per_word;
unsigned speed;
spi_fd = open("/dev/spidev0.0", O_RDWR);
if (spi_fd < 0) {
fprintf(stderr, "[rpiezos] Error! opening spi device failed\n");
return -1;
}
mode = SPI_MODE_0;
bits_per_word = 8;
speed = 1000000;
rc = ioctl(spi_fd, SPI_IOC_WR_MODE, &mode);
if (rc != 0) {
printf("[rpiezos] Error! ioctl failed, "
"cound not set SPI mode (WR)\n");
return rc;
}
rc = ioctl(spi_fd, SPI_IOC_RD_MODE, &mode);
if (rc != 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed, "
"cound not set SPI mode (RD)\n");
return rc;
}
rc = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word);
if (rc != 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed, "
"cound not set SPI bits per word (WR)\n");
return rc;
}
rc = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits_per_word);
if (rc != 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed, "
"cound not set SPI bits per word (RD) \n");
return rc;
}
rc = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (rc != 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed, "
"cound not set SPI speed (WR) \n");
return rc;
}
rc = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (rc != 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed, "
"cound not set SPI speed (RD) \n");
return rc;
}
// --------- osc client setup -------------
lo_address dest = lo_address_new(config.ip, config.port);
// --------- main loop --------------------
while (running) {
for (unsigned p = 0; p < NUM_PIEZOS; ++p) {
unsigned char data[3];
data[0] = 1;
data[1] = (unsigned char)(0b10000000 | (((p & 7) << 4)));
data[2] = 0;
struct spi_ioc_transfer spi[3];
int i = 0;
int ret_val = -1;
memset(spi, 0, sizeof(spi)); // ioctl struct must be zeroed
for (i = 0; i < 3; i++) {
spi[i].tx_buf = (unsigned long)(data + i); // transmit from "data"
spi[i].rx_buf = (unsigned long)(data + i); // receive into "data"
spi[i].len = sizeof(data[i]);
spi[i].delay_usecs = 0;
spi[i].speed_hz = speed;
spi[i].bits_per_word = bits_per_word;
spi[i].cs_change = 0;
}
ret_val = ioctl(spi_fd, SPI_IOC_MESSAGE(3), &spi);
if (ret_val < 0) {
fprintf(stderr, "[rpiezos] Error! ioctl failed durint "
"spi data transfer\n");
return -1;
}
int a2d_val = 0;
a2d_val = (data[1] << 8) & 0b1100000000;
a2d_val |= (data[2] & 0xff);
if (piezos[p].enabled) {
float range = (float)(piezos[p].max - piezos[p].min);
float pct = (float)(a2d_val - piezos[p].min);
float value = pct / range;
if (value < 0.0f) {
value = 0.0f;
}
if (value > 1.0f) {
value = 1.0f;
}
if (value != piezos[p].z1) {
lo_send(dest, config.address, "if", p, value);
piezos[p].z1 = value;
if (config.verbose) {
printf("[rpiezos] n %d | a2d value = %d | output = %f\n",
p, a2d_val, value);
}
}
}
}
usec_sleep(config.sleep_usecs);
}
lo_address_free(dest);
return 0;
}
void quit_handler(int signo)
{
if (signo == SIGINT || signo == SIGTERM) {
printf("\nreceived SIGINT or SIGTERM, quitting...\n");
running = 0;
}
}
void usec_sleep(long int usecs)
{
struct timespec tim, tim2;
tim.tv_sec = 0;
tim.tv_nsec = usecs * 1000;
nanosleep(&tim, &tim2);
}
int parse_piezo(char * arg, struct piezo_t * piezos)
{
size_t len = strlen(arg);
int mode = 0;
int min = 0;
int max = 1024;
for (int i = 0; i < NUM_PIEZOS; ++i) {
piezos[i].mark = 0;
}
for (unsigned i = 0; i < len; ++i) {
int c = (int)arg[i];
switch (mode) {
case 0:
if (c >= '0' && c <= '5') {
int p = c - '0';
piezos[p].mark = 1;
}
if (c == ':') {
mode = 1;
min = 0;
}
break;
case 1:
if (c >= '0' && c <= '9') {
int n = c - '0';
min = n + min * 10;
}
if (c == ':') {
mode = 2;
max = 0;
}
case 2:
if (c >= '0' && c <= '9') {
int n = c - '0';
max = n + max * 10;
}
if (c == ':') {
mode = 2;
}
}
}
if (min >= 1024) {
fprintf(stderr, "[rpiezos] min value should be lower than 1024");
return -1;
}
if (max > 1024) {
fprintf(stderr, "[rpiezos] min value should not be greater than 1024");
return -1;
}
for (int i = 0; i < NUM_PIEZOS; ++i) {
if (piezos[i].mark) {
piezos[i].enabled = 1;
piezos[i].min = min;
piezos[i].max = max;
}
}
return 0;
}
int parse_args(int argc, char * argv[], struct piezo_t * piezos, struct config_t * config)
{
int has_port = 0;
int has_piezos = 0;
int c;
for (c = 0; c < argc; ++c) {
if (argv[c][0] == '-') {
switch (argv[c][1]) {
case 'i':
if (c < argc - 1) {
config->ip = argv[c + 1];
c++;
}
break;
case 'p':
if (c < argc - 1) {
config->port = argv[c + 1];
has_port = 1;
c++;
}
break;
case 'a':
if (c < argc - 1) {
config->address = argv[c + 1];
c++;
}
break;
case 's':
if (c < argc - 1) {
int rc = parse_piezo(argv[c + 1], piezos);
if (rc != 0) {
return rc;
}
has_piezos = 1;
c++;
}
break;
case 'u':
if (c < argc - 1) {
config->sleep_usecs = atol(argv[c + 1]);
c++;
}
break;
case 'v':
config->verbose = 1;
break;
default:
break;
}
}
}
if (!has_port) {
fprintf(stderr, "[rpiezos] destination port not given!"
" use the -p argument to set it\n");
return -1;
}
if (!has_piezos) {
fprintf(stderr, "[rpiezos] no piezo sensor activated, use -s to set it\n"
" for example -s 124 to activate sensors 1, 2 and 4\n");
return -1;
}
return 0;
}