/******************************************************************************!
* \file adc.c
* \author Sebastien Beaugrand
* \sa http://beaugrand.chez.com/
* \copyright CeCILL 2.1 Free Software license
******************************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <math.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/tcp.h>
#include <time.h>
#include "wiring.h"
#include "debug.h"
#define CLOCK CLOCK_REALTIME
#ifdef SINUS
void analogSetFrequencies(int argc, char* argv[]);
#endif
const char* PORT = "4040";
int gSock = 0;
struct timespec gTimeval;
time_t gOffset;
/******************************************************************************!
* \fn controlC
******************************************************************************/
void controlC(int sig)
{
if (sig == SIGINT) {
analogQuit();
if (gSock != 0) {
close(gSock);
}
exit(EXIT_SUCCESS);
}
}
/******************************************************************************!
* \fn sockInit
******************************************************************************/
void sockInit(const char* port)
{
struct addrinfo ahints;
struct addrinfo* ares;
struct addrinfo* aiter;
memset(&ahints, 0, sizeof(struct addrinfo));
ahints.ai_family = AF_INET;
ahints.ai_socktype = SOCK_DGRAM;
ahints.ai_flags = AI_PASSIVE;
ahints.ai_protocol = IPPROTO_UDP;
ahints.ai_canonname = NULL;
ahints.ai_addr = NULL;
ahints.ai_next = NULL;
if (getaddrinfo(NULL, port, &ahints, &ares) != 0) {
ERRNO("getaddrinfo");
exit(EXIT_FAILURE);
}
for (aiter = ares; aiter != NULL; aiter = aiter->ai_next) {
if ((gSock = socket(aiter->ai_family,
aiter->ai_socktype,
aiter->ai_protocol)) == -1) {
continue;
}
if (bind(gSock, aiter->ai_addr, aiter->ai_addrlen) == 0) {
break;
}
close(gSock);
gSock = 0;
}
if (aiter == NULL) {
ERROR("bind");
exit(EXIT_FAILURE);
}
freeaddrinfo(ares);
}
/******************************************************************************!
* \fn main
******************************************************************************/
int main(int argc, char* argv[])
{
const unsigned int HEADER_SIZE = sizeof(uint32_t) << 1;
const unsigned int SAMPLE_SIZE = 1 << (int) log2(TCP_MSS_DEFAULT -
HEADER_SIZE);
const unsigned int PACKET_SIZE = HEADER_SIZE + SAMPLE_SIZE;
struct sockaddr_in addr;
uint16_t buff[PACKET_SIZE >> 1];
unsigned int pos;
uint16_t uint2;
uint32_t uint4;
socklen_t slen = sizeof(addr);
uint32_t count;
# ifdef ARIETTA
uint32_t sleep;
if (argc > 1) {
sleep = 1 << atoi(argv[1]);
} else {
sleep = 1 << 18;
}
# else
struct timespec ts;
DEBUG("TCP_MSS_DEFAULT = %d", TCP_MSS_DEFAULT);
DEBUG("SAMPLE_SIZE = %d", SAMPLE_SIZE);
DEBUG("PACKET_SIZE = %d", PACKET_SIZE);
clock_getres(CLOCK_REALTIME, &ts);
DEBUG("%lu.%09lu CLOCK_REALTIME", ts.tv_sec, ts.tv_nsec);
clock_getres(CLOCK_MONOTONIC, &ts);
DEBUG("%lu.%09lu CLOCK_MONOTONIC", ts.tv_sec, ts.tv_nsec);
clock_getres(CLOCK_MONOTONIC_RAW, &ts);
DEBUG("%lu.%09lu CLOCK_MONOTONIC_RAW", ts.tv_sec, ts.tv_nsec);
clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
DEBUG("%lu.%09lu CLOCK_PROCESS_CPUTIME_ID", ts.tv_sec, ts.tv_nsec);
clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts);
DEBUG("%lu.%09lu CLOCK_THREAD_CPUTIME_ID", ts.tv_sec, ts.tv_nsec);
if (argc > 1) {
ts.tv_sec = 0;
ts.tv_nsec = 1000000000 / atoi(argv[1]);
} else {
ts.tv_sec = 0;
ts.tv_nsec = 1;
}
# endif
# ifdef SINUS
analogSetFrequencies(argc, argv);
# endif
if (! analogInit()) {
ERROR("analogInit");
exit(EXIT_FAILURE);
}
if (clock_gettime(CLOCK, &gTimeval) < 0) {
ERRNO("clock_gettime");
exit(EXIT_FAILURE);
}
gOffset = gTimeval.tv_sec;
count = 0;
pos = 0;
buff[pos++] = 0;
buff[pos++] = 0;
buff[pos++] = SAMPLE_SIZE >> 16;
buff[pos++] = SAMPLE_SIZE & 0xFFFFu;
if (signal(SIGINT, controlC) == SIG_ERR) {
ERRNO("signal");
exit(EXIT_FAILURE);
}
sockInit(PORT);
if (recvfrom(gSock, buff, PACKET_SIZE, 0,
(struct sockaddr*) &addr, &slen) < 0) {
ERRNO("recvfrom");
exit(EXIT_FAILURE);
}
for (;;) {
if (clock_gettime(CLOCK, &gTimeval) < 0) {
ERRNO("clock_gettime");
exit(EXIT_FAILURE);
}
uint2 = (uint16_t) (gTimeval.tv_sec - gOffset);
buff[pos++] = uint2;
uint4 = (uint32_t) (gTimeval.tv_nsec / 1000);
buff[pos++] = uint4 >> 16;
buff[pos++] = uint4 & 0xFFFFu;
buff[pos++] = analogRead(0);
if (pos == (PACKET_SIZE >> 1)) {
if (sendto(gSock, buff, pos << 1, 0,
(struct sockaddr*) &addr, slen) < 0) {
ERRNO("send");
exit(EXIT_FAILURE);
}
++count;
pos = 0;
buff[pos++] = count >> 16;
buff[pos++] = count & 0xFFFFu;
buff[pos++] = SAMPLE_SIZE >> 16;
buff[pos++] = SAMPLE_SIZE & 0xFFFFu;
}
# ifdef ARIETTA
for (uint4 = 0; uint4 < sleep; ++uint4) {
;
}
# else
clock_nanosleep(CLOCK, 0, &ts, NULL);
# endif
}
}